mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
345 lines
9.9 KiB
C++
345 lines
9.9 KiB
C++
/* Copyright (c) 2011, 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 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-1335 USA */
|
|
|
|
#include "mariadb.h"
|
|
#include "sql_list.h" // Sql_alloc, List, List_iterator
|
|
#include "sql_cmd.h" // Sql_cmd
|
|
#include "sql_class.h" // Diagnostics_area
|
|
#include "sql_get_diagnostics.h" // Sql_cmd_get_diagnostics
|
|
|
|
/**
|
|
Execute this GET DIAGNOSTICS statement.
|
|
|
|
@param thd The current thread.
|
|
|
|
@remark Errors or warnings occurring during the execution of the GET
|
|
DIAGNOSTICS statement should not affect the diagnostics area
|
|
of a previous statement as the diagnostics information there
|
|
would be wiped out. Thus, in order to preserve the contents
|
|
of the diagnostics area from which information is being
|
|
retrieved, the GET DIAGNOSTICS statement is executed under
|
|
a separate diagnostics area. If any errors or warnings occur
|
|
during the execution of the GET DIAGNOSTICS statement, these
|
|
error or warnings (conditions) are appended to the list of
|
|
the original diagnostics area. The only exception to this is
|
|
fatal errors, which must always cause the statement to fail.
|
|
|
|
@retval false on success.
|
|
@retval true on error
|
|
*/
|
|
|
|
bool
|
|
Sql_cmd_get_diagnostics::execute(THD *thd)
|
|
{
|
|
bool rv;
|
|
Diagnostics_area new_stmt_da(thd->query_id, false, true);
|
|
Diagnostics_area *save_stmt_da= thd->get_stmt_da();
|
|
DBUG_ENTER("Sql_cmd_get_diagnostics::execute");
|
|
|
|
/* Disable the unneeded read-only mode of the original DA. */
|
|
save_stmt_da->set_warning_info_read_only(false);
|
|
|
|
/* Set new diagnostics area, execute statement and restore. */
|
|
thd->set_stmt_da(&new_stmt_da);
|
|
rv= m_info->aggregate(thd, save_stmt_da);
|
|
thd->set_stmt_da(save_stmt_da);
|
|
|
|
/* Bail out early if statement succeeded. */
|
|
if (! rv)
|
|
{
|
|
thd->get_stmt_da()->set_ok_status(0, 0, NULL);
|
|
DBUG_RETURN(false);
|
|
}
|
|
|
|
/* Statement failed, retrieve the error information for propagation. */
|
|
uint sql_errno= new_stmt_da.sql_errno();
|
|
const char *message= new_stmt_da.message();
|
|
const char *sqlstate= new_stmt_da.get_sqlstate();
|
|
|
|
/* In case of a fatal error, set it into the original DA.*/
|
|
if (unlikely(thd->is_fatal_error))
|
|
{
|
|
save_stmt_da->set_error_status(sql_errno, message, sqlstate, NULL);
|
|
DBUG_RETURN(true);
|
|
}
|
|
|
|
/* Otherwise, just append the new error as a exception condition. */
|
|
save_stmt_da->push_warning(thd, sql_errno, sqlstate,
|
|
Sql_condition::WARN_LEVEL_ERROR,
|
|
message);
|
|
|
|
/* Appending might have failed. */
|
|
if (unlikely(!(rv= thd->is_error())))
|
|
thd->get_stmt_da()->set_ok_status(0, 0, NULL);
|
|
|
|
DBUG_RETURN(rv);
|
|
}
|
|
|
|
|
|
/**
|
|
Set a value for this item.
|
|
|
|
@param thd The current thread.
|
|
@param value The obtained value.
|
|
|
|
@retval false on success.
|
|
@retval true on error.
|
|
*/
|
|
|
|
bool
|
|
Diagnostics_information_item::set_value(THD *thd, Item **value)
|
|
{
|
|
bool rv;
|
|
Settable_routine_parameter *srp;
|
|
DBUG_ENTER("Diagnostics_information_item::set_value");
|
|
|
|
/* Get a settable reference to the target. */
|
|
srp= m_target->get_settable_routine_parameter();
|
|
|
|
DBUG_ASSERT(srp);
|
|
|
|
/* GET DIAGNOSTICS is not allowed in prepared statements */
|
|
DBUG_ASSERT(srp->get_item_param() == NULL);
|
|
|
|
/* Set variable/parameter value. */
|
|
rv= srp->set_value(thd, thd->spcont, value);
|
|
|
|
DBUG_RETURN(rv);
|
|
}
|
|
|
|
|
|
/**
|
|
Obtain statement information in the context of a given diagnostics area.
|
|
|
|
@param thd The current thread.
|
|
@param da The diagnostics area.
|
|
|
|
@retval false on success.
|
|
@retval true on error
|
|
*/
|
|
|
|
bool
|
|
Statement_information::aggregate(THD *thd, const Diagnostics_area *da)
|
|
{
|
|
bool rv= false;
|
|
Statement_information_item *stmt_info_item;
|
|
List_iterator<Statement_information_item> it(*m_items);
|
|
DBUG_ENTER("Statement_information::aggregate");
|
|
|
|
/*
|
|
Each specified target gets the value of each given
|
|
information item obtained from the diagnostics area.
|
|
*/
|
|
while ((stmt_info_item= it++))
|
|
{
|
|
if ((rv= evaluate(thd, stmt_info_item, da)))
|
|
break;
|
|
}
|
|
|
|
DBUG_RETURN(rv);
|
|
}
|
|
|
|
|
|
/**
|
|
Obtain the value of this statement information item in the context of
|
|
a given diagnostics area.
|
|
|
|
@param thd The current thread.
|
|
@param da The diagnostics area.
|
|
|
|
@retval Item representing the value.
|
|
@retval NULL on error.
|
|
*/
|
|
|
|
Item *
|
|
Statement_information_item::get_value(THD *thd, const Diagnostics_area *da)
|
|
{
|
|
Item *value= NULL;
|
|
DBUG_ENTER("Statement_information_item::get_value");
|
|
|
|
switch (m_name)
|
|
{
|
|
/*
|
|
The number of condition areas that have information. That is,
|
|
the number of errors and warnings within the diagnostics area.
|
|
*/
|
|
case NUMBER:
|
|
{
|
|
ulong count= da->cond_count();
|
|
value= new (thd->mem_root) Item_uint(thd, count);
|
|
break;
|
|
}
|
|
/*
|
|
Number that shows how many rows were directly affected by
|
|
a data-change statement (INSERT, UPDATE, DELETE, MERGE,
|
|
REPLACE, LOAD).
|
|
*/
|
|
case ROW_COUNT:
|
|
value= new (thd->mem_root) Item_int(thd, thd->get_row_count_func());
|
|
break;
|
|
}
|
|
|
|
DBUG_RETURN(value);
|
|
}
|
|
|
|
|
|
/**
|
|
Obtain condition information in the context of a given diagnostics area.
|
|
|
|
@param thd The current thread.
|
|
@param da The diagnostics area.
|
|
|
|
@retval false on success.
|
|
@retval true on error
|
|
*/
|
|
|
|
bool
|
|
Condition_information::aggregate(THD *thd, const Diagnostics_area *da)
|
|
{
|
|
bool rv= false;
|
|
longlong cond_number;
|
|
const Sql_condition *cond= NULL;
|
|
Condition_information_item *cond_info_item;
|
|
Diagnostics_area::Sql_condition_iterator it_conds= da->sql_conditions();
|
|
List_iterator_fast<Condition_information_item> it_items(*m_items);
|
|
DBUG_ENTER("Condition_information::aggregate");
|
|
|
|
/* Prepare the expression for evaluation. */
|
|
if (m_cond_number_expr->fix_fields_if_needed(thd, &m_cond_number_expr))
|
|
DBUG_RETURN(true);
|
|
|
|
cond_number= m_cond_number_expr->val_int();
|
|
|
|
/*
|
|
Limit to the number of available conditions. Warning_info::warn_count()
|
|
is not used because it indicates the number of condition regardless of
|
|
@@max_error_count, which prevents conditions from being pushed, but not
|
|
counted.
|
|
*/
|
|
if (cond_number < 1 || (ulonglong) cond_number > da->cond_count())
|
|
{
|
|
my_error(ER_DA_INVALID_CONDITION_NUMBER, MYF(0));
|
|
DBUG_RETURN(true);
|
|
}
|
|
|
|
/* Advance to the requested condition. */
|
|
while (cond_number--)
|
|
cond= it_conds++;
|
|
|
|
DBUG_ASSERT(cond);
|
|
|
|
/* Evaluate the requested information in the context of the condition. */
|
|
while ((cond_info_item= it_items++))
|
|
{
|
|
if ((rv= evaluate(thd, cond_info_item, cond)))
|
|
break;
|
|
}
|
|
|
|
DBUG_RETURN(rv);
|
|
}
|
|
|
|
|
|
/**
|
|
Create an UTF-8 string item to represent a condition item string.
|
|
|
|
@remark The string might not have a associated charset. For example,
|
|
this can be the case if the server does not or fails to process
|
|
the error message file.
|
|
|
|
@remark See "Design notes about Sql_condition::m_message_text." in sql_error.cc
|
|
|
|
@return Pointer to an string item, NULL on failure.
|
|
*/
|
|
|
|
Item *
|
|
Condition_information_item::make_utf8_string_item(THD *thd, const String *str)
|
|
{
|
|
/* Default is utf8 character set and utf8_general_ci collation. */
|
|
CHARSET_INFO *to_cs= &my_charset_utf8_general_ci;
|
|
/* If a charset was not set, assume that no conversion is needed. */
|
|
CHARSET_INFO *from_cs= str->charset() ? str->charset() : to_cs;
|
|
String tmp(str->ptr(), str->length(), from_cs);
|
|
/* If necessary, convert the string (ignoring errors), then copy it over. */
|
|
uint conv_errors;
|
|
return new (thd->mem_root) Item_string(thd, &tmp, to_cs, &conv_errors,
|
|
DERIVATION_COERCIBLE, MY_REPERTOIRE_UNICODE30);
|
|
}
|
|
|
|
|
|
/**
|
|
Obtain the value of this condition information item in the context of
|
|
a given condition.
|
|
|
|
@param thd The current thread.
|
|
@param da The diagnostics area.
|
|
|
|
@retval Item representing the value.
|
|
@retval NULL on error.
|
|
*/
|
|
|
|
Item *
|
|
Condition_information_item::get_value(THD *thd, const Sql_condition *cond)
|
|
{
|
|
String str;
|
|
Item *value= NULL;
|
|
DBUG_ENTER("Condition_information_item::get_value");
|
|
|
|
switch (m_name)
|
|
{
|
|
case CLASS_ORIGIN:
|
|
value= make_utf8_string_item(thd, &(cond->m_class_origin));
|
|
break;
|
|
case SUBCLASS_ORIGIN:
|
|
value= make_utf8_string_item(thd, &(cond->m_subclass_origin));
|
|
break;
|
|
case CONSTRAINT_CATALOG:
|
|
value= make_utf8_string_item(thd, &(cond->m_constraint_catalog));
|
|
break;
|
|
case CONSTRAINT_SCHEMA:
|
|
value= make_utf8_string_item(thd, &(cond->m_constraint_schema));
|
|
break;
|
|
case CONSTRAINT_NAME:
|
|
value= make_utf8_string_item(thd, &(cond->m_constraint_name));
|
|
break;
|
|
case CATALOG_NAME:
|
|
value= make_utf8_string_item(thd, &(cond->m_catalog_name));
|
|
break;
|
|
case SCHEMA_NAME:
|
|
value= make_utf8_string_item(thd, &(cond->m_schema_name));
|
|
break;
|
|
case TABLE_NAME:
|
|
value= make_utf8_string_item(thd, &(cond->m_table_name));
|
|
break;
|
|
case COLUMN_NAME:
|
|
value= make_utf8_string_item(thd, &(cond->m_column_name));
|
|
break;
|
|
case CURSOR_NAME:
|
|
value= make_utf8_string_item(thd, &(cond->m_cursor_name));
|
|
break;
|
|
case MESSAGE_TEXT:
|
|
value= make_utf8_string_item(thd, &(cond->m_message_text));
|
|
break;
|
|
case MYSQL_ERRNO:
|
|
value= new (thd->mem_root) Item_uint(thd, cond->m_sql_errno);
|
|
break;
|
|
case RETURNED_SQLSTATE:
|
|
str.set_ascii(cond->get_sqlstate(), strlen(cond->get_sqlstate()));
|
|
value= make_utf8_string_item(thd, &str);
|
|
break;
|
|
}
|
|
|
|
DBUG_RETURN(value);
|
|
}
|
|
|