用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
9.7 KiB

5 months ago
// Copyright (c) 2017, 2018, 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.
/// @file
///
/// This file implements the CREATE/DROP SPATIAL REFERENCE SYSTEM statements.
#include "sql/sql_cmd_srs.h"
#include <string>
#include "scope_guard.h" // create_scope_guard
#include "sql/auth/auth_acls.h" // SUPER_ACL
#include "sql/binlog.h" // mysql_bin_log
#include "sql/dd/cache/dictionary_client.h"
#include "sql/dd/dd.h" // dd::create_object
#include "sql/dd/impl/types/spatial_reference_system_impl.h"
#include "sql/dd/types/spatial_reference_system.h"
#include "sql/derror.h" // ER_THD
#include "sql/gis/srid.h" // gis::srid_t
#include "sql/lock.h" // acquire_shared_global...
#include "sql/sql_backup_lock.h" // acquire_shared_backup_lock
#include "sql/sql_class.h" // THD
#include "sql/sql_prepare.h" // Ed_connection
#include "sql/srs_fetcher.h"
#include "sql/strfunc.h"
#include "sql/thd_raii.h" // Disable_autocommit_guard
#include "sql/transaction.h"
/// Issue a warning if an SRID is within one of the reserved ranges.
///
/// @param[in] srid The SRID to check.
/// @param[in] thd Thread context.
static void warn_if_in_reserved_range(gis::srid_t srid, THD *thd) {
gis::srid_t min = 0;
gis::srid_t max = 0;
if (srid <= 32767) {
// Reserved by EPSG, cf. OGP Publication 373-7-1 Geomatics Guidance Note
// number 7, part 1 - August 2012, Sect 5.9.
min = 0;
max = 32767;
} else if (srid >= 60000000 && srid <= 69999999) {
// Reserved by EPSG, cf. OGP Publication 373-7-1 Geomatics Guidance Note
// number 7, part 1 - August 2012, Sect 5.9.
min = 60000000;
max = 69999999;
} else if (srid >= 2000000000 && srid <= 2147483647) {
// Reserved by MySQL.
min = 2000000000;
max = 2147483647;
}
if (!(min == 0 && max == 0)) {
push_warning_printf(thd, Sql_condition::SL_WARNING,
ER_WARN_RESERVED_SRID_RANGE,
ER_THD(thd, ER_WARN_RESERVED_SRID_RANGE), min, max);
}
}
/// Check if an SRS is used, i.e., if any columns depend on it.
///
/// @param[in] srid The SRID.
/// @param[in] thd Thread context.
///
/// @retval true The SRS is used by at least one column.
/// @retval false The SRS is not used by any columns.
static bool srs_is_used(gis::srid_t srid, THD *thd) {
// We can't drop an SRS if it is used by a column (i.e., the column type has
// an SRID type modifier referencing this SRS). Ideally, we'd like a foreign
// key constraint to enforce this, but while waiting for the data dictionary
// to enforce those, we have to do a workaround.
//
// Ed_connection doesn't handle statements that return a result, so instead of
// selecting the list of columns using this SRS from the I_S views, we use a
// DO statement that will fail with an error if the SRID is in use. Since it
// is a DO statement, it will never return any result on success.
Ed_connection conn(thd);
std::string query(
"DO (SELECT ST_GEOMETRYTYPE('invalid') FROM "
"INFORMATION_SCHEMA.ST_GEOMETRY_COLUMNS WHERE SRS_ID=");
query.append(std::to_string(srid));
query.append(");");
MYSQL_LEX_STRING query_string;
lex_string_strmake(thd->mem_root, &query_string, query.c_str(),
query.length());
return conn.execute_direct(query_string);
}
bool Sql_cmd_create_srs::fill_srs(dd::Spatial_reference_system *srs) {
DBUG_ASSERT(m_srs_name.str != nullptr);
srs->set_name(m_srs_name.str);
if (m_organization.str != nullptr) {
srs->set_organization(m_organization.str);
srs->set_organization_coordsys_id(m_organization_coordsys_id);
} else {
srs->set_organization(nullptr);
srs->set_organization_coordsys_id(nullptr);
}
if (m_description.str != nullptr)
srs->set_description(m_description.str);
else
srs->set_description(nullptr);
DBUG_ASSERT(m_definition.str != nullptr);
srs->set_definition(m_definition.str);
return static_cast<dd::Spatial_reference_system_impl *>(srs)
->parse_definition();
}
/// Abort the current statement and transaction.
///
/// @param[in] thd Thread context.
///
/// @retval false Success.
/// @retval true An error occurred.
static bool rollback(THD *thd) {
bool error = trans_rollback_stmt(thd);
error |= trans_rollback(thd);
return error;
}
/// Commit the current statement and transaction.
///
/// @param[in] thd Thread context.
///
/// @retval false Success.
/// @retval true An error occurred.
static bool commit(THD *thd) {
if (mysql_bin_log.is_open() &&
thd->binlog_query(THD::STMT_QUERY_TYPE, thd->query().str,
thd->query().length, true, false, false, 0)) {
/* purecov: begin inspected */
rollback(thd);
return true;
/* purecov: end */
}
return (trans_commit_stmt(thd) || trans_commit(thd));
}
bool Sql_cmd_create_srs::execute(THD *thd) {
if (!(thd->security_context()->check_access(SUPER_ACL))) {
my_error(ER_CMD_NEED_SUPER, MYF(0),
m_or_replace ? "CREATE OR REPLACE SPATIAL REFERENCE SYSTEM"
: "CREATE SPATIAL REFERENCE SYSTEM");
return true;
}
if (acquire_shared_global_read_lock(thd, thd->variables.lock_wait_timeout) ||
acquire_shared_backup_lock(thd, thd->variables.lock_wait_timeout))
return true;
Disable_autocommit_guard dag(thd);
dd::cache::Dictionary_client *dd_client = thd->dd_client();
dd::cache::Dictionary_client::Auto_releaser releaser(dd_client);
auto rollback_guard = create_scope_guard([thd]() {
if (rollback(thd)) DBUG_ASSERT(false); /* purecov: deadcode */
});
Srs_fetcher fetcher(thd);
dd::Spatial_reference_system *srs = nullptr;
if (fetcher.acquire_for_modification(m_srid, &srs))
return true; /* purecov: inspected */
if (srs != nullptr) {
if (m_if_not_exists) {
push_warning_printf(thd, Sql_condition::SL_WARNING,
ER_WARN_SRS_ID_ALREADY_EXISTS,
ER_THD(thd, ER_WARN_SRS_ID_ALREADY_EXISTS), m_srid);
my_ok(thd);
return false;
}
if (!m_or_replace) {
my_error(ER_SRS_ID_ALREADY_EXISTS, MYF(0), m_srid);
return true;
}
if (fill_srs(srs)) return true; // Error has already been flagged.
const dd::Spatial_reference_system *old_srs = nullptr;
if (fetcher.acquire(m_srid, &old_srs)) return true; /* purecov: inspected */
DBUG_ASSERT(old_srs != nullptr);
if (srs_is_used(m_srid, thd) && !old_srs->can_be_modified_to(*srs)) {
my_error(ER_CANT_MODIFY_SRS_USED_BY_COLUMN, MYF(0), m_srid);
return true;
}
warn_if_in_reserved_range(m_srid, thd);
if (dd_client->update(srs)) return true; // Error has already been flagged.
rollback_guard.commit();
if (commit(thd)) return true; /* purecov: inspected */
my_ok(thd);
return false;
}
std::unique_ptr<dd::Spatial_reference_system> new_srs(
dd::create_object<dd::Spatial_reference_system>());
static_cast<dd::Spatial_reference_system_impl *>(new_srs.get())
->set_id(m_srid);
if (fill_srs(new_srs.get())) return true; // Error has already been flagged.
warn_if_in_reserved_range(m_srid, thd);
if (thd->dd_client()->store(new_srs.get())) return true;
rollback_guard.commit();
if (commit(thd)) return true; /* purecov: inspected */
my_ok(thd);
return false;
}
bool Sql_cmd_drop_srs::execute(THD *thd) {
if (!(thd->security_context()->check_access(SUPER_ACL))) {
my_error(ER_CMD_NEED_SUPER, MYF(0), "DROP SPATIAL REFERENCE SYSTEM");
return true;
}
if (acquire_shared_global_read_lock(thd, thd->variables.lock_wait_timeout) ||
acquire_shared_backup_lock(thd, thd->variables.lock_wait_timeout))
return true;
Disable_autocommit_guard dag(thd);
dd::cache::Dictionary_client *dd_client = thd->dd_client();
dd::cache::Dictionary_client::Auto_releaser releaser(dd_client);
auto rollback_guard = create_scope_guard([thd]() {
if (rollback(thd)) DBUG_ASSERT(false); /* purecov: deadcode */
});
Srs_fetcher fetcher(thd);
dd::Spatial_reference_system *srs = nullptr;
if (fetcher.acquire_for_modification(m_srid, &srs))
return true; /* purecov: inspected */
if (srs == nullptr) {
if (m_if_exists) {
push_warning_printf(thd, Sql_condition::SL_WARNING, ER_WARN_SRS_NOT_FOUND,
ER_THD(thd, ER_SRS_NOT_FOUND), m_srid);
my_ok(thd);
} else {
my_error(ER_SRS_NOT_FOUND, MYF(0), m_srid);
}
return !m_if_exists;
}
warn_if_in_reserved_range(m_srid, thd);
if (srs_is_used(m_srid, thd)) {
my_error(ER_CANT_MODIFY_SRS_USED_BY_COLUMN, MYF(0), m_srid);
return true;
}
if (dd_client->drop(srs)) return true; /* purecov: inspected */
rollback_guard.commit();
if (commit(thd)) return true; /* purecov: inspected */
my_ok(thd);
return false;
}