mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
07e4853c23
MDEV-17625 Different warnings when comparing a garbage to DATETIME vs TIME - Splitting processes of data type conversion (to TIME/DATE,DATETIME) and warning generation. Warning are now only get collected during conversion (in an "int" variable), and are pushed in the very end of conversion (not in parallel). Warnings generated by the low level routines str_to_xxx() and number_to_xxx() can now be changed at the end, when TIME_FUZZY_DATES is applied, from "Invalid value" to "Truncated invalid value". Now "Illegal value" is issued only when the low level routine returned an error and TIME_FUZZY_DATES was not set. Otherwise, if the low level routine returned "false" (success), or if NULL was converted to a zero datetime by TIME_FUZZY_DATES, then "Truncated illegal value" is issued. This gives better warnings. - Methods Type_handler::Item_get_date() and Type_handler::Item_func_hybrid_field_type_get_date() now only convert and collect warning information, but do not push warnings. - Changing the return data type for Type_handler::Item_get_date() and Type_handler::Item_func_hybrid_field_type_get_date() from "bool" to "void". The conversion result (success vs error) can be checked by testing ltime->time_type. MYSQL_TIME_{NONE|ERROR} mean mean error, other values mean success. - Adding new wrapper methods Type_handler::Item_get_date_with_warn() and Type_handler::Item_func_hybrid_field_type_get_date_with_warn() to do conversion followed by raising warnings, and changing the code to call new Type_handler::***_with_warn() methods. - Adding a helper class Temporal::Status, a wrapper for MYSQL_TIME_STATUS with automatic initialization. - Adding a helper class Temporal::Warn, to collect warnings but without actually raising them. Moving a part of ErrConv into a separate class ErrBuff, and deriving both Temporal::Warn and ErrConv from ErrBuff. The ErrBuff part of Temporal::Warn is used to collect textual representation of the input data. - Adding a helper class Temporal::Warn_push. It's used to collect warning information during conversion, and automatically pushes warnings to the diagnostics area on its destructor time (in case of non-zero warning). - Moving more code from various functions inside class Temporal. - Adding more Temporal_hybrid constructors and protected Temporal methods make_from_xxx(), which convert and only collect warning information, but do not actually raise warnings. - Now the low level functions str_to_datetime() and str_to_time() always set status->warning if the return value is "true" (error). - Now the low level functions number_to_time() and number_to_datetime() set the "*was_cut" argument if the return value is "true" (error). - Adding a few DBUG_ASSERTs to make sure that str_to_xxx() and number_to_xxx() always set warnings on error. - Adding new warning flags MYSQL_TIME_WARN_EDOM and MYSQL_TIME_WARN_ZERO_DATE for the code symmetry. Before this change there was a special code path for (rc==true && was_cut==0) which was treated by Field_temporal::store_invalid_with_warning as "zero date violation". Now was_cut==0 always means that there are no any error/warnings/notes to be raised, not matter what rc is. - Using new Temporal_hybrid constructors in combination with Temporal::Warn_push inside str_to_datetime_with_warn(), double_to_datetime_with_warn(), int_to_datetime_with_warn(), Field::get_date(), Item::get_date_from_string(), and a few other places. - Removing methods Dec_ptr::to_datetime_with_warn(), Year::to_time_with_warn(), my_decimal::to_datetime_with_warn(), Dec_ptr::to_datetime_with_warn(). Fixing Sec6::to_time() and Sec6::to_datetime() to convert and only collect warnings, without raising warnings. Now warning raising functionality resides in Temporal::Warn_push. - Adding classes Longlong_hybrid_null and Double_null, to return both value and the "IS NULL" flag. Adding methods Item::to_double_null(), to_longlong_hybrid_null(), Item_func_hybrid_field_type::to_longlong_hybrid_null_op(), Item_func_hybrid_field_type::to_double_null_op(). Removing separate classes VInt and VInt_op, as they have been replaced by a single class Longlong_hybrid_null. - Adding a helper method Temporal::type_name_by_timestamp_type(), moving a part of make_truncated_value_warning() into it, and reusing in Temporal::Warn::push_conversion_warnings(). - Removing Item::make_zero_date() and Item_func_hybrid_field_type::make_zero_mysql_time(). They provided duplicate functionality. Now this code resides in Temporal::make_fuzzy_date(). The latter is now called for all Item types when data type conversion (to DATE/TIME/DATETIME) is involved, including Item_field and Item_direct_view_ref. This fixes MDEV-17563: Item_direct_view_ref now correctly converts NULL to a zero date when TIME_FUZZY_DATES says so.
182 lines
6 KiB
C++
182 lines
6 KiB
C++
#ifndef PROCEDURE_INCLUDED
|
|
#define PROCEDURE_INCLUDED
|
|
|
|
/* Copyright (c) 2000, 2010, 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-1301 USA */
|
|
|
|
/* When using sql procedures */
|
|
|
|
#ifdef USE_PRAGMA_INTERFACE
|
|
#pragma interface /* gcc class implementation */
|
|
#endif
|
|
|
|
/*
|
|
It is necessary to include set_var.h instead of item.h because there
|
|
are dependencies on include order for set_var.h and item.h. This
|
|
will be resolved later.
|
|
*/
|
|
#include "sql_class.h" /* select_result, set_var.h: THD */
|
|
#include "set_var.h" /* Item */
|
|
|
|
#define PROC_NO_SORT 1 /**< Bits in flags */
|
|
#define PROC_GROUP 2 /**< proc must have group */
|
|
|
|
/* Procedure items used by procedures to store values for send_result_set_metadata */
|
|
|
|
class Item_proc :public Item
|
|
{
|
|
public:
|
|
Item_proc(THD *thd, const char *name_par): Item(thd)
|
|
{
|
|
this->name.str= name_par;
|
|
this->name.length= strlen(name_par);
|
|
}
|
|
enum Type type() const { return Item::PROC_ITEM; }
|
|
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
|
|
const Tmp_field_param *param)
|
|
{
|
|
/*
|
|
We can get to here when using a CURSOR for a query with PROCEDURE:
|
|
DECLARE c CURSOR FOR SELECT * FROM t1 PROCEDURE analyse();
|
|
OPEN c;
|
|
*/
|
|
return create_tmp_field_ex_simple(table, src, param);
|
|
}
|
|
virtual void set(double nr)=0;
|
|
virtual void set(const char *str,uint length,CHARSET_INFO *cs)=0;
|
|
virtual void set(longlong nr)=0;
|
|
const Type_handler *type_handler() const=0;
|
|
void set(const char *str) { set(str,(uint) strlen(str), default_charset()); }
|
|
void make_send_field(THD *thd, Send_field *tmp_field)
|
|
{
|
|
init_make_send_field(tmp_field,field_type());
|
|
}
|
|
unsigned int size_of() { return sizeof(*this);}
|
|
bool check_vcol_func_processor(void *arg)
|
|
{
|
|
DBUG_ASSERT(0); // impossible
|
|
return mark_unsupported_function("proc", arg, VCOL_IMPOSSIBLE);
|
|
}
|
|
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
|
|
{
|
|
return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
|
|
}
|
|
Item* get_copy(THD *thd) { return 0; }
|
|
};
|
|
|
|
class Item_proc_real :public Item_proc
|
|
{
|
|
double value;
|
|
public:
|
|
Item_proc_real(THD *thd, const char *name_par, uint dec):
|
|
Item_proc(thd, name_par)
|
|
{
|
|
decimals=dec; max_length=float_length(dec);
|
|
}
|
|
const Type_handler *type_handler() const { return &type_handler_double; }
|
|
void set(double nr) { value=nr; }
|
|
void set(longlong nr) { value=(double) nr; }
|
|
void set(const char *str,uint length,CHARSET_INFO *cs)
|
|
{
|
|
int err_not_used;
|
|
char *end_not_used;
|
|
value= my_strntod(cs,(char*) str,length, &end_not_used, &err_not_used);
|
|
}
|
|
double val_real() { return value; }
|
|
longlong val_int() { return (longlong) value; }
|
|
String *val_str(String *s)
|
|
{
|
|
s->set_real(value,decimals,default_charset());
|
|
return s;
|
|
}
|
|
my_decimal *val_decimal(my_decimal *);
|
|
unsigned int size_of() { return sizeof(*this);}
|
|
};
|
|
|
|
class Item_proc_int :public Item_proc
|
|
{
|
|
longlong value;
|
|
public:
|
|
Item_proc_int(THD *thd, const char *name_par): Item_proc(thd, name_par)
|
|
{ max_length=11; }
|
|
const Type_handler *type_handler() const { return &type_handler_longlong; }
|
|
void set(double nr) { value=(longlong) nr; }
|
|
void set(longlong nr) { value=nr; }
|
|
void set(const char *str,uint length, CHARSET_INFO *cs)
|
|
{ int err; value=my_strntoll(cs,str,length,10,NULL,&err); }
|
|
double val_real() { return (double) value; }
|
|
longlong val_int() { return value; }
|
|
String *val_str(String *s) { s->set(value, default_charset()); return s; }
|
|
my_decimal *val_decimal(my_decimal *);
|
|
unsigned int size_of() { return sizeof(*this);}
|
|
};
|
|
|
|
|
|
class Item_proc_string :public Item_proc
|
|
{
|
|
public:
|
|
Item_proc_string(THD *thd, const char *name_par, uint length):
|
|
Item_proc(thd, name_par) { this->max_length=length; }
|
|
const Type_handler *type_handler() const { return &type_handler_varchar; }
|
|
void set(double nr) { str_value.set_real(nr, 2, default_charset()); }
|
|
void set(longlong nr) { str_value.set(nr, default_charset()); }
|
|
void set(const char *str, uint length, CHARSET_INFO *cs)
|
|
{ str_value.copy(str,length,cs); }
|
|
double val_real()
|
|
{
|
|
int err_not_used;
|
|
char *end_not_used;
|
|
CHARSET_INFO *cs= str_value.charset();
|
|
return my_strntod(cs, (char*) str_value.ptr(), str_value.length(),
|
|
&end_not_used, &err_not_used);
|
|
}
|
|
longlong val_int()
|
|
{
|
|
int err;
|
|
CHARSET_INFO *cs=str_value.charset();
|
|
return my_strntoll(cs,str_value.ptr(),str_value.length(),10,NULL,&err);
|
|
}
|
|
String *val_str(String*)
|
|
{
|
|
return null_value ? (String*) 0 : (String*) &str_value;
|
|
}
|
|
my_decimal *val_decimal(my_decimal *);
|
|
unsigned int size_of() { return sizeof(*this);}
|
|
};
|
|
|
|
/* The procedure class definitions */
|
|
|
|
class Procedure {
|
|
protected:
|
|
List<Item> *fields;
|
|
select_result *result;
|
|
public:
|
|
const uint flags;
|
|
ORDER *group,*param_fields;
|
|
Procedure(select_result *res,uint flags_par) :result(res),flags(flags_par),
|
|
group(0),param_fields(0) {}
|
|
virtual ~Procedure() {group=param_fields=0; fields=0; }
|
|
virtual void add(void)=0;
|
|
virtual void end_group(void)=0;
|
|
virtual int send_row(List<Item> &fields)=0;
|
|
virtual bool change_columns(THD *thd, List<Item> &fields)= 0;
|
|
virtual void update_refs(void) {}
|
|
virtual int end_of_records() { return 0; }
|
|
};
|
|
|
|
Procedure *setup_procedure(THD *thd,ORDER *proc_param,select_result *result,
|
|
List<Item> &field_list,int *error);
|
|
|
|
#endif /* PROCEDURE_INCLUDED */
|