/* Copyright (C) 2000-2006 MySQL AB 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef DRIZZLED_SERVER_ITEM_FUNC_H #define DRIZZLED_SERVER_ITEM_FUNC_H /* Function items used by mysql */ #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif #ifdef HAVE_IEEEFP_H extern "C" /* Bug in BSDI include file */ { #include } #endif class Item_func :public Item_result_field { protected: Item **args, *tmp_arg[2]; /* Allowed numbers of columns in result (usually 1, which means scalar value) 0 means get this number from first argument */ uint allowed_arg_cols; public: uint arg_count; table_map used_tables_cache, not_null_tables_cache; bool const_item_cache; enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, GE_FUNC,GT_FUNC, LIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC, COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, BETWEEN, IN_FUNC, MULT_EQUAL_FUNC, INTERVAL_FUNC, ISNOTNULLTEST_FUNC, NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC, NEG_FUNC }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; enum Type type() const { return FUNC_ITEM; } virtual enum Functype functype() const { return UNKNOWN_FUNC; } Item_func(void): allowed_arg_cols(1), arg_count(0) { with_sum_func= 0; } Item_func(Item *a): allowed_arg_cols(1), arg_count(1) { args= tmp_arg; args[0]= a; with_sum_func= a->with_sum_func; } Item_func(Item *a,Item *b): allowed_arg_cols(1), arg_count(2) { args= tmp_arg; args[0]= a; args[1]= b; with_sum_func= a->with_sum_func || b->with_sum_func; } Item_func(Item *a,Item *b,Item *c): allowed_arg_cols(1) { arg_count= 0; if ((args= (Item**) sql_alloc(sizeof(Item*)*3))) { arg_count= 3; args[0]= a; args[1]= b; args[2]= c; with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func; } } Item_func(Item *a,Item *b,Item *c,Item *d): allowed_arg_cols(1) { arg_count= 0; if ((args= (Item**) sql_alloc(sizeof(Item*)*4))) { arg_count= 4; args[0]= a; args[1]= b; args[2]= c; args[3]= d; with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func || d->with_sum_func; } } Item_func(Item *a,Item *b,Item *c,Item *d,Item* e): allowed_arg_cols(1) { arg_count= 5; if ((args= (Item**) sql_alloc(sizeof(Item*)*5))) { args[0]= a; args[1]= b; args[2]= c; args[3]= d; args[4]= e; with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func || d->with_sum_func || e->with_sum_func ; } } Item_func(List &list); // Constructor used for Item_cond_and/or (see Item comment) Item_func(THD *thd, Item_func *item); bool fix_fields(THD *, Item **ref); void fix_after_pullout(st_select_lex *new_parent, Item **ref); table_map used_tables() const; table_map not_null_tables() const; void update_used_tables(); bool eq(const Item *item, bool binary_cmp) const; virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; } virtual bool have_rev_func() const { return 0; } virtual Item *key_item() const { return args[0]; } /* This method is used for debug purposes to print the name of an item to the debug log. The second use of this method is as a helper function of print(), where it is applicable. To suit both goals it should return a meaningful, distinguishable and sintactically correct string. This method should not be used for runtime type identification, use enum {Sum}Functype and Item_func::functype()/Item_sum::sum_func() instead. */ virtual const char *func_name() const= 0; virtual bool const_item() const { return const_item_cache; } inline Item **arguments() const { return args; } void set_arguments(List &list); inline uint argument_count() const { return arg_count; } inline void remove_arguments() { arg_count=0; } void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields); virtual void print(String *str, enum_query_type query_type); void print_op(String *str, enum_query_type query_type); void print_args(String *str, uint from, enum_query_type query_type); virtual void fix_num_length_and_dec(); void count_only_length(); void count_real_length(); void count_decimal_length(); inline bool get_arg0_date(DRIZZLE_TIME *ltime, uint fuzzy_date) { return (null_value=args[0]->get_date(ltime, fuzzy_date)); } inline bool get_arg0_time(DRIZZLE_TIME *ltime) { return (null_value=args[0]->get_time(ltime)); } bool is_null() { update_null_value(); return null_value; } void signal_divide_by_null(); friend class udf_handler; Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg); Item *get_tmp_table_item(THD *thd); my_decimal *val_decimal(my_decimal *); bool agg_arg_collations(DTCollation &c, Item **items, uint nitems, uint flags) { return agg_item_collations(c, func_name(), items, nitems, flags, 1); } bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems, uint flags) { return agg_item_collations_for_comparison(c, func_name(), items, nitems, flags); } bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems, uint flags, int item_sep) { return agg_item_charsets(c, func_name(), items, nitems, flags, item_sep); } bool walk(Item_processor processor, bool walk_subquery, uchar *arg); Item *transform(Item_transformer transformer, uchar *arg); Item* compile(Item_analyzer analyzer, uchar **arg_p, Item_transformer transformer, uchar *arg_t); void traverse_cond(Cond_traverser traverser, void * arg, traverse_order order); inline double fix_result(double value) { if (isfinite(value)) return value; null_value=1; return 0.0; } }; class Item_real_func :public Item_func { public: Item_real_func() :Item_func() {} Item_real_func(Item *a) :Item_func(a) {} Item_real_func(Item *a,Item *b) :Item_func(a,b) {} Item_real_func(List &list) :Item_func(list) {} String *val_str(String*str); my_decimal *val_decimal(my_decimal *decimal_value); int64_t val_int() { assert(fixed == 1); return (int64_t) rint(val_real()); } enum Item_result result_type () const { return REAL_RESULT; } void fix_length_and_dec() { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } }; class Item_func_numhybrid: public Item_func { protected: Item_result hybrid_type; public: Item_func_numhybrid(Item *a) :Item_func(a), hybrid_type(REAL_RESULT) {} Item_func_numhybrid(Item *a,Item *b) :Item_func(a,b), hybrid_type(REAL_RESULT) {} Item_func_numhybrid(List &list) :Item_func(list), hybrid_type(REAL_RESULT) {} enum Item_result result_type () const { return hybrid_type; } void fix_length_and_dec(); void fix_num_length_and_dec(); virtual void find_num_type()= 0; /* To be called from fix_length_and_dec */ double val_real(); int64_t val_int(); my_decimal *val_decimal(my_decimal *); String *val_str(String*str); /** @brief Performs the operation that this functions implements when the result type is INT. @return The result of the operation. */ virtual int64_t int_op()= 0; /** @brief Performs the operation that this functions implements when the result type is REAL. @return The result of the operation. */ virtual double real_op()= 0; /** @brief Performs the operation that this functions implements when the result type is DECIMAL. @param A pointer where the DECIMAL value will be allocated. @return - 0 If the result is NULL - The same pointer it was given, with the area initialized to the result of the operation. */ virtual my_decimal *decimal_op(my_decimal *)= 0; /** @brief Performs the operation that this functions implements when the result type is a string type. @return The result of the operation. */ virtual String *str_op(String *)= 0; bool is_null() { update_null_value(); return null_value; } }; /* function where type of result detected by first argument */ class Item_func_num1: public Item_func_numhybrid { public: Item_func_num1(Item *a) :Item_func_numhybrid(a) {} Item_func_num1(Item *a, Item *b) :Item_func_numhybrid(a, b) {} void fix_num_length_and_dec(); void find_num_type(); String *str_op(String *str __attribute__((unused))) { assert(0); return 0; } }; /* Base class for operations like '+', '-', '*' */ class Item_num_op :public Item_func_numhybrid { public: Item_num_op(Item *a,Item *b) :Item_func_numhybrid(a, b) {} virtual void result_precision()= 0; virtual inline void print(String *str, enum_query_type query_type) { print_op(str, query_type); } void find_num_type(); String *str_op(String *str __attribute__((unused))) { assert(0); return 0; } }; class Item_int_func :public Item_func { public: Item_int_func() :Item_func() { max_length= 21; } Item_int_func(Item *a) :Item_func(a) { max_length= 21; } Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length= 21; } Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { max_length= 21; } Item_int_func(List &list) :Item_func(list) { max_length= 21; } Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) {} double val_real(); String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() {} }; class Item_func_connection_id :public Item_int_func { int64_t value; public: Item_func_connection_id() {} const char *func_name() const { return "connection_id"; } void fix_length_and_dec(); bool fix_fields(THD *thd, Item **ref); int64_t val_int() { assert(fixed == 1); return value; } }; class Item_func_signed :public Item_int_func { public: Item_func_signed(Item *a) :Item_int_func(a) {} const char *func_name() const { return "cast_as_signed"; } int64_t val_int(); int64_t val_int_from_str(int *error); void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=0; } virtual void print(String *str, enum_query_type query_type); uint decimal_precision() const { return args[0]->decimal_precision(); } }; class Item_func_unsigned :public Item_func_signed { public: Item_func_unsigned(Item *a) :Item_func_signed(a) {} const char *func_name() const { return "cast_as_unsigned"; } void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=1; } int64_t val_int(); virtual void print(String *str, enum_query_type query_type); }; class Item_decimal_typecast :public Item_func { my_decimal decimal_value; public: Item_decimal_typecast(Item *a, int len, int dec) :Item_func(a) { decimals= dec; max_length= my_decimal_precision_to_length(len, dec, unsigned_flag); } String *val_str(String *str); double val_real(); int64_t val_int(); my_decimal *val_decimal(my_decimal*); enum Item_result result_type () const { return DECIMAL_RESULT; } enum_field_types field_type() const { return DRIZZLE_TYPE_NEWDECIMAL; } void fix_length_and_dec() {}; const char *func_name() const { return "decimal_typecast"; } virtual void print(String *str, enum_query_type query_type); }; class Item_func_additive_op :public Item_num_op { public: Item_func_additive_op(Item *a,Item *b) :Item_num_op(a,b) {} void result_precision(); }; class Item_func_plus :public Item_func_additive_op { public: Item_func_plus(Item *a,Item *b) :Item_func_additive_op(a,b) {} const char *func_name() const { return "+"; } int64_t int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); }; class Item_func_minus :public Item_func_additive_op { public: Item_func_minus(Item *a,Item *b) :Item_func_additive_op(a,b) {} const char *func_name() const { return "-"; } int64_t int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); void fix_length_and_dec(); }; class Item_func_mul :public Item_num_op { public: Item_func_mul(Item *a,Item *b) :Item_num_op(a,b) {} const char *func_name() const { return "*"; } int64_t int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); void result_precision(); }; class Item_func_div :public Item_num_op { public: uint prec_increment; Item_func_div(Item *a,Item *b) :Item_num_op(a,b) {} int64_t int_op() { assert(0); return 0; } double real_op(); my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "/"; } void fix_length_and_dec(); void result_precision(); }; class Item_func_int_div :public Item_int_func { public: Item_func_int_div(Item *a,Item *b) :Item_int_func(a,b) {} int64_t val_int(); const char *func_name() const { return "DIV"; } void fix_length_and_dec(); virtual inline void print(String *str, enum_query_type query_type) { print_op(str, query_type); } }; class Item_func_mod :public Item_num_op { public: Item_func_mod(Item *a,Item *b) :Item_num_op(a,b) {} int64_t int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "%"; } void result_precision(); void fix_length_and_dec(); }; class Item_func_neg :public Item_func_num1 { public: Item_func_neg(Item *a) :Item_func_num1(a) {} double real_op(); int64_t int_op(); my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "-"; } enum Functype functype() const { return NEG_FUNC; } void fix_length_and_dec(); void fix_num_length_and_dec(); uint decimal_precision() const { return args[0]->decimal_precision(); } }; class Item_func_abs :public Item_func_num1 { public: Item_func_abs(Item *a) :Item_func_num1(a) {} double real_op(); int64_t int_op(); my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "abs"; } void fix_length_and_dec(); }; // A class to handle logarithmic and trigonometric functions class Item_dec_func :public Item_real_func { public: Item_dec_func(Item *a) :Item_real_func(a) {} Item_dec_func(Item *a,Item *b) :Item_real_func(a,b) {} void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); maybe_null=1; } }; class Item_func_exp :public Item_dec_func { public: Item_func_exp(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "exp"; } }; class Item_func_ln :public Item_dec_func { public: Item_func_ln(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "ln"; } }; class Item_func_log :public Item_dec_func { public: Item_func_log(Item *a) :Item_dec_func(a) {} Item_func_log(Item *a,Item *b) :Item_dec_func(a,b) {} double val_real(); const char *func_name() const { return "log"; } }; class Item_func_log2 :public Item_dec_func { public: Item_func_log2(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "log2"; } }; class Item_func_log10 :public Item_dec_func { public: Item_func_log10(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "log10"; } }; class Item_func_sqrt :public Item_dec_func { public: Item_func_sqrt(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "sqrt"; } }; class Item_func_pow :public Item_dec_func { public: Item_func_pow(Item *a,Item *b) :Item_dec_func(a,b) {} double val_real(); const char *func_name() const { return "pow"; } }; class Item_func_acos :public Item_dec_func { public: Item_func_acos(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "acos"; } }; class Item_func_asin :public Item_dec_func { public: Item_func_asin(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "asin"; } }; class Item_func_atan :public Item_dec_func { public: Item_func_atan(Item *a) :Item_dec_func(a) {} Item_func_atan(Item *a,Item *b) :Item_dec_func(a,b) {} double val_real(); const char *func_name() const { return "atan"; } }; class Item_func_cos :public Item_dec_func { public: Item_func_cos(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "cos"; } }; class Item_func_sin :public Item_dec_func { public: Item_func_sin(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "sin"; } }; class Item_func_tan :public Item_dec_func { public: Item_func_tan(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "tan"; } }; class Item_func_integer :public Item_int_func { public: inline Item_func_integer(Item *a) :Item_int_func(a) {} void fix_length_and_dec(); }; class Item_func_int_val :public Item_func_num1 { public: Item_func_int_val(Item *a) :Item_func_num1(a) {} void fix_num_length_and_dec(); void find_num_type(); }; class Item_func_ceiling :public Item_func_int_val { public: Item_func_ceiling(Item *a) :Item_func_int_val(a) {} const char *func_name() const { return "ceiling"; } int64_t int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); }; class Item_func_floor :public Item_func_int_val { public: Item_func_floor(Item *a) :Item_func_int_val(a) {} const char *func_name() const { return "floor"; } int64_t int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); }; /* This handles round and truncate */ class Item_func_round :public Item_func_num1 { bool truncate; public: Item_func_round(Item *a, Item *b, bool trunc_arg) :Item_func_num1(a,b), truncate(trunc_arg) {} const char *func_name() const { return truncate ? "truncate" : "round"; } double real_op(); int64_t int_op(); my_decimal *decimal_op(my_decimal *); void fix_length_and_dec(); }; class Item_func_rand :public Item_real_func { struct rand_struct *rand; public: Item_func_rand(Item *a) :Item_real_func(a), rand(0) {} Item_func_rand() :Item_real_func() {} double val_real(); const char *func_name() const { return "rand"; } bool const_item() const { return 0; } void update_used_tables(); bool fix_fields(THD *thd, Item **ref); private: void seed_random (Item * val); }; class Item_func_sign :public Item_int_func { public: Item_func_sign(Item *a) :Item_int_func(a) {} const char *func_name() const { return "sign"; } int64_t val_int(); }; class Item_func_units :public Item_real_func { char *name; double mul,add; public: Item_func_units(char *name_arg,Item *a,double mul_arg,double add_arg) :Item_real_func(a),name(name_arg),mul(mul_arg),add(add_arg) {} double val_real(); const char *func_name() const { return name; } void fix_length_and_dec() { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } }; class Item_func_min_max :public Item_func { Item_result cmp_type; String tmp_value; int cmp_sign; /* TRUE <=> arguments should be compared in the DATETIME context. */ bool compare_as_dates; /* An item used for issuing warnings while string to DATETIME conversion. */ Item *datetime_item; THD *thd; protected: enum_field_types cached_field_type; public: Item_func_min_max(List &list,int cmp_sign_arg) :Item_func(list), cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(false), datetime_item(0) {} double val_real(); int64_t val_int(); String *val_str(String *); my_decimal *val_decimal(my_decimal *); void fix_length_and_dec(); enum Item_result result_type () const { return cmp_type; } bool result_as_int64_t() { return compare_as_dates; }; uint cmp_datetimes(uint64_t *value); enum_field_types field_type() const { return cached_field_type; } }; class Item_func_min :public Item_func_min_max { public: Item_func_min(List &list) :Item_func_min_max(list,1) {} const char *func_name() const { return "least"; } }; class Item_func_max :public Item_func_min_max { public: Item_func_max(List &list) :Item_func_min_max(list,-1) {} const char *func_name() const { return "greatest"; } }; /* Objects of this class are used for ROLLUP queries to wrap up each constant item referred to in GROUP BY list. */ class Item_func_rollup_const :public Item_func { public: Item_func_rollup_const(Item *a) :Item_func(a) { name= a->name; name_length= a->name_length; } double val_real() { return args[0]->val_real(); } int64_t val_int() { return args[0]->val_int(); } String *val_str(String *str) { return args[0]->val_str(str); } my_decimal *val_decimal(my_decimal *dec) { return args[0]->val_decimal(dec); } const char *func_name() const { return "rollup_const"; } bool const_item() const { return 0; } Item_result result_type() const { return args[0]->result_type(); } void fix_length_and_dec() { collation= args[0]->collation; max_length= args[0]->max_length; decimals=args[0]->decimals; /* The item could be a NULL constant. */ null_value= args[0]->is_null(); } }; class Item_func_length :public Item_int_func { String value; public: Item_func_length(Item *a) :Item_int_func(a) {} int64_t val_int(); const char *func_name() const { return "length"; } void fix_length_and_dec() { max_length=10; } }; class Item_func_bit_length :public Item_func_length { public: Item_func_bit_length(Item *a) :Item_func_length(a) {} int64_t val_int() { assert(fixed == 1); return Item_func_length::val_int()*8; } const char *func_name() const { return "bit_length"; } }; class Item_func_char_length :public Item_int_func { String value; public: Item_func_char_length(Item *a) :Item_int_func(a) {} int64_t val_int(); const char *func_name() const { return "char_length"; } void fix_length_and_dec() { max_length=10; } }; class Item_func_coercibility :public Item_int_func { public: Item_func_coercibility(Item *a) :Item_int_func(a) {} int64_t val_int(); const char *func_name() const { return "coercibility"; } void fix_length_and_dec() { max_length=10; maybe_null= 0; } table_map not_null_tables() const { return 0; } }; class Item_func_locate :public Item_int_func { String value1,value2; DTCollation cmp_collation; public: Item_func_locate(Item *a,Item *b) :Item_int_func(a,b) {} Item_func_locate(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} const char *func_name() const { return "locate"; } int64_t val_int(); void fix_length_and_dec(); virtual void print(String *str, enum_query_type query_type); }; class Item_func_field :public Item_int_func { String value,tmp; Item_result cmp_type; DTCollation cmp_collation; public: Item_func_field(List &list) :Item_int_func(list) {} int64_t val_int(); const char *func_name() const { return "field"; } void fix_length_and_dec(); }; class Item_func_ascii :public Item_int_func { String value; public: Item_func_ascii(Item *a) :Item_int_func(a) {} int64_t val_int(); const char *func_name() const { return "ascii"; } void fix_length_and_dec() { max_length=3; } }; class Item_func_ord :public Item_int_func { String value; public: Item_func_ord(Item *a) :Item_int_func(a) {} int64_t val_int(); const char *func_name() const { return "ord"; } }; class Item_func_find_in_set :public Item_int_func { String value,value2; uint enum_value; uint64_t enum_bit; DTCollation cmp_collation; public: Item_func_find_in_set(Item *a,Item *b) :Item_int_func(a,b),enum_value(0) {} int64_t val_int(); const char *func_name() const { return "find_in_set"; } void fix_length_and_dec(); }; /* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */ class Item_func_bit: public Item_int_func { public: Item_func_bit(Item *a, Item *b) :Item_int_func(a, b) {} Item_func_bit(Item *a) :Item_int_func(a) {} void fix_length_and_dec() { unsigned_flag= 1; } virtual inline void print(String *str, enum_query_type query_type) { print_op(str, query_type); } }; class Item_func_bit_or :public Item_func_bit { public: Item_func_bit_or(Item *a, Item *b) :Item_func_bit(a, b) {} int64_t val_int(); const char *func_name() const { return "|"; } }; class Item_func_bit_and :public Item_func_bit { public: Item_func_bit_and(Item *a, Item *b) :Item_func_bit(a, b) {} int64_t val_int(); const char *func_name() const { return "&"; } }; class Item_func_bit_count :public Item_int_func { public: Item_func_bit_count(Item *a) :Item_int_func(a) {} int64_t val_int(); const char *func_name() const { return "bit_count"; } void fix_length_and_dec() { max_length=2; } }; class Item_func_shift_left :public Item_func_bit { public: Item_func_shift_left(Item *a, Item *b) :Item_func_bit(a, b) {} int64_t val_int(); const char *func_name() const { return "<<"; } }; class Item_func_shift_right :public Item_func_bit { public: Item_func_shift_right(Item *a, Item *b) :Item_func_bit(a, b) {} int64_t val_int(); const char *func_name() const { return ">>"; } }; class Item_func_bit_neg :public Item_func_bit { public: Item_func_bit_neg(Item *a) :Item_func_bit(a) {} int64_t val_int(); const char *func_name() const { return "~"; } virtual inline void print(String *str, enum_query_type query_type) { Item_func::print(str, query_type); } }; class Item_func_last_insert_id :public Item_int_func { public: Item_func_last_insert_id() :Item_int_func() {} Item_func_last_insert_id(Item *a) :Item_int_func(a) {} int64_t val_int(); const char *func_name() const { return "last_insert_id"; } void fix_length_and_dec() { if (arg_count) max_length= args[0]->max_length; } bool fix_fields(THD *thd, Item **ref); }; class Item_func_benchmark :public Item_int_func { public: Item_func_benchmark(Item *count_expr, Item *expr) :Item_int_func(count_expr, expr) {} int64_t val_int(); const char *func_name() const { return "benchmark"; } void fix_length_and_dec() { max_length=1; maybe_null=0; } virtual void print(String *str, enum_query_type query_type); }; class Item_udf_func :public Item_func { protected: udf_handler udf; bool is_expensive_processor(uchar *arg __attribute__((unused))) { return true; } public: Item_udf_func(udf_func *udf_arg) :Item_func(), udf(udf_arg) {} Item_udf_func(udf_func *udf_arg, List &list) :Item_func(list), udf(udf_arg) {} const char *func_name() const { return udf.name(); } enum Functype functype() const { return UDF_FUNC; } bool fix_fields(THD *thd, Item **ref __attribute__((unused))) { assert(fixed == 0); bool res= udf.fix_fields(thd, this, arg_count, args); used_tables_cache= udf.used_tables_cache; const_item_cache= udf.const_item_cache; fixed= 1; return res; } void update_used_tables() { /* TODO: Make a member in UDF_INIT and return if a UDF is deterministic or not. Currently UDF_INIT has a member (const_item) that is an in/out parameter to the init() call. The code in udf_handler::fix_fields also duplicates the arguments handling code in Item_func::fix_fields(). The lack of information if a UDF is deterministic makes writing a correct update_used_tables() for UDFs impossible. One solution to this would be : - Add a is_deterministic member of UDF_INIT - (optionally) deprecate the const_item member of UDF_INIT - Take away the duplicate code from udf_handler::fix_fields() and make Item_udf_func call Item_func::fix_fields() to process its arguments as for any other function. - Store the deterministic flag returned by _init into the udf_handler. - Don't implement Item_udf_func::fix_fields, implement Item_udf_func::fix_length_and_dec() instead (similar to non-UDF functions). - Override Item_func::update_used_tables to call Item_func::update_used_tables() and add a RAND_TABLE_BIT to the result of Item_func::update_used_tables() if the UDF is non-deterministic. - (optionally) rename RAND_TABLE_BIT to NONDETERMINISTIC_BIT to better describe its usage. The above would require a change of the UDF API. Until that change is done here's how the current code works: We call Item_func::update_used_tables() only when we know that the function depends on real non-const tables and is deterministic. This can be done only because we know that the optimizer will call update_used_tables() only when there's possibly a new const table. So update_used_tables() can only make a Item_func more constant than it is currently. That's why we don't need to do anything if a function is guaranteed to return non-constant (it's non-deterministic) or is already a const. */ if ((used_tables_cache & ~PSEUDO_TABLE_BITS) && !(used_tables_cache & RAND_TABLE_BIT)) { Item_func::update_used_tables(); if (!const_item_cache && !used_tables_cache) used_tables_cache= RAND_TABLE_BIT; } } void cleanup(); Item_result result_type () const { return udf.result_type(); } table_map not_null_tables() const { return 0; } virtual void print(String *str, enum_query_type query_type); }; class Item_func_udf_float :public Item_udf_func { public: Item_func_udf_float(udf_func *udf_arg) :Item_udf_func(udf_arg) {} Item_func_udf_float(udf_func *udf_arg, List &list) :Item_udf_func(udf_arg, list) {} int64_t val_int() { assert(fixed == 1); return (int64_t) rint(Item_func_udf_float::val_real()); } my_decimal *val_decimal(my_decimal *dec_buf) { double res=val_real(); if (null_value) return NULL; double2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf); return dec_buf; } double val_real(); String *val_str(String *str); void fix_length_and_dec() { fix_num_length_and_dec(); } }; class Item_func_udf_int :public Item_udf_func { public: Item_func_udf_int(udf_func *udf_arg) :Item_udf_func(udf_arg) {} Item_func_udf_int(udf_func *udf_arg, List &list) :Item_udf_func(udf_arg, list) {} int64_t val_int(); double val_real() { return (double) Item_func_udf_int::val_int(); } String *val_str(String *str); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals= 0; max_length= 21; } }; class Item_func_udf_decimal :public Item_udf_func { public: Item_func_udf_decimal(udf_func *udf_arg) :Item_udf_func(udf_arg) {} Item_func_udf_decimal(udf_func *udf_arg, List &list) :Item_udf_func(udf_arg, list) {} int64_t val_int(); double val_real(); my_decimal *val_decimal(my_decimal *); String *val_str(String *str); enum Item_result result_type () const { return DECIMAL_RESULT; } void fix_length_and_dec(); }; class Item_func_udf_str :public Item_udf_func { public: Item_func_udf_str(udf_func *udf_arg) :Item_udf_func(udf_arg) {} Item_func_udf_str(udf_func *udf_arg, List &list) :Item_udf_func(udf_arg, list) {} String *val_str(String *); double val_real() { int err_not_used; char *end_not_used; String *res; res= val_str(&str_value); return res ? my_strntod(res->charset(),(char*) res->ptr(), res->length(), &end_not_used, &err_not_used) : 0.0; } int64_t val_int() { int err_not_used; String *res; res=val_str(&str_value); return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err_not_used) : (int64_t) 0; } my_decimal *val_decimal(my_decimal *dec_buf) { String *res=val_str(&str_value); if (!res) return NULL; string2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf); return dec_buf; } enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); }; /* replication functions */ class Item_master_pos_wait :public Item_int_func { String value; public: Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {} Item_master_pos_wait(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} int64_t val_int(); const char *func_name() const { return "master_pos_wait"; } void fix_length_and_dec() { max_length=21; maybe_null=1;} }; /* Handling of user definable variables */ class user_var_entry; class Item_func_set_user_var :public Item_func { enum Item_result cached_result_type; user_var_entry *entry; char buffer[MAX_FIELD_WIDTH]; String value; my_decimal decimal_buff; bool null_item; union { int64_t vint; double vreal; String *vstr; my_decimal *vdec; } save_result; public: LEX_STRING name; // keep it public Item_func_set_user_var(LEX_STRING a,Item *b) :Item_func(b), cached_result_type(INT_RESULT), name(a) {} enum Functype functype() const { return SUSERVAR_FUNC; } double val_real(); int64_t val_int(); String *val_str(String *str); my_decimal *val_decimal(my_decimal *); double val_result(); int64_t val_int_result(); String *str_result(String *str); my_decimal *val_decimal_result(my_decimal *); bool update_hash(void *ptr, uint length, enum Item_result type, CHARSET_INFO *cs, Derivation dv, bool unsigned_arg); bool send(Protocol *protocol, String *str_arg); void make_field(Send_field *tmp_field); bool check(bool use_result_field); bool update(); enum Item_result result_type () const { return cached_result_type; } bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); virtual void print(String *str, enum_query_type query_type); void print_as_stmt(String *str, enum_query_type query_type); const char *func_name() const { return "set_user_var"; } int save_in_field(Field *field, bool no_conversions, bool can_use_result_field); int save_in_field(Field *field, bool no_conversions) { return save_in_field(field, no_conversions, 1); } void save_org_in_field(Field *field) { (void)save_in_field(field, 1, 0); } bool register_field_in_read_map(uchar *arg); }; class Item_func_get_user_var :public Item_func { user_var_entry *var_entry; Item_result m_cached_result_type; public: LEX_STRING name; // keep it public Item_func_get_user_var(LEX_STRING a): Item_func(), m_cached_result_type(STRING_RESULT), name(a) {} enum Functype functype() const { return GUSERVAR_FUNC; } LEX_STRING get_name() { return name; } double val_real(); int64_t val_int(); my_decimal *val_decimal(my_decimal*); String *val_str(String* str); void fix_length_and_dec(); virtual void print(String *str, enum_query_type query_type); enum Item_result result_type() const; /* We must always return variables as strings to guard against selects of type select @t1:=1,@t1,@t:="hello",@t from foo where (@t1:= t2.b) */ const char *func_name() const { return "get_user_var"; } bool const_item() const; table_map used_tables() const { return const_item() ? 0 : RAND_TABLE_BIT; } bool eq(const Item *item, bool binary_cmp) const; }; /* This item represents user variable used as out parameter (e.g in LOAD DATA), and it is supposed to be used only for this purprose. So it is simplified a lot. Actually you should never obtain its value. The only two reasons for this thing being an Item is possibility to store it in List and desire to place this code somewhere near other functions working with user variables. */ class Item_user_var_as_out_param :public Item { LEX_STRING name; user_var_entry *entry; public: Item_user_var_as_out_param(LEX_STRING a) : name(a) {} /* We should return something different from FIELD_ITEM here */ enum Type type() const { return STRING_ITEM;} double val_real(); int64_t val_int(); String *val_str(String *str); my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ bool fix_fields(THD *thd, Item **ref); virtual void print(String *str, enum_query_type query_type); void set_null_value(CHARSET_INFO* cs); void set_value(const char *str, uint length, CHARSET_INFO* cs); }; /* A system variable */ class Item_func_get_system_var :public Item_func { sys_var *var; enum_var_type var_type; LEX_STRING component; public: Item_func_get_system_var(sys_var *var_arg, enum_var_type var_type_arg, LEX_STRING *component_arg, const char *name_arg, size_t name_len_arg); bool fix_fields(THD *thd, Item **ref); /* Stubs for pure virtual methods. Should never be called: this item is always substituted with a constant in fix_fields(). */ double val_real() { assert(0); return 0.0; } int64_t val_int() { assert(0); return 0; } String* val_str(String*) { assert(0); return 0; } void fix_length_and_dec() { assert(0); } /* TODO: fix to support views */ const char *func_name() const { return "get_system_var"; } /** Indicates whether this system variable is written to the binlog or not. Variables are written to the binlog as part of "status_vars" in Query_log_event, as an Intvar_log_event, or a Rand_log_event. @return true if the variable is written to the binlog, false otherwise. */ bool is_written_to_binlog(); }; class Item_func_bit_xor : public Item_func_bit { public: Item_func_bit_xor(Item *a, Item *b) :Item_func_bit(a, b) {} int64_t val_int(); const char *func_name() const { return "^"; } }; class Item_func_is_free_lock :public Item_int_func { String value; public: Item_func_is_free_lock(Item *a) :Item_int_func(a) {} int64_t val_int(); const char *func_name() const { return "is_free_lock"; } void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;} }; class Item_func_is_used_lock :public Item_int_func { String value; public: Item_func_is_used_lock(Item *a) :Item_int_func(a) {} int64_t val_int(); const char *func_name() const { return "is_used_lock"; } void fix_length_and_dec() { decimals=0; max_length=10; maybe_null=1;} }; /* For type casts */ enum Cast_target { ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT, ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR, ITEM_CAST_DECIMAL }; class Item_func_row_count :public Item_int_func { public: Item_func_row_count() :Item_int_func() {} int64_t val_int(); const char *func_name() const { return "row_count"; } void fix_length_and_dec() { decimals= 0; maybe_null=0; } }; /* * * Stored FUNCTIONs * */ struct st_sp_security_context; class Item_func_found_rows :public Item_int_func { public: Item_func_found_rows() :Item_int_func() {} int64_t val_int(); const char *func_name() const { return "found_rows"; } void fix_length_and_dec() { decimals= 0; maybe_null=0; } }; #endif /* DRIZZLE_SERVER_ITEM_FUNC_H */