diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 3 | ||||
-rw-r--r-- | sql/item.h | 18 | ||||
-rw-r--r-- | sql/sp_head.cc | 45 | ||||
-rw-r--r-- | sql/sp_rcontext.cc | 63 | ||||
-rw-r--r-- | sql/sp_rcontext.h | 7 | ||||
-rw-r--r-- | sql/sql_class.cc | 3 |
6 files changed, 97 insertions, 42 deletions
diff --git a/sql/item.cc b/sql/item.cc index f105d97bec2..a28cc261b3c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -298,7 +298,7 @@ longlong Item::val_int_from_decimal() Item::Item(): - name(0), orig_name(0), name_length(0), fixed(0), + rsize(0), name(0), orig_name(0), name_length(0), fixed(0), collation(&my_charset_bin, DERIVATION_COERCIBLE) { marker= 0; @@ -330,6 +330,7 @@ Item::Item(): tables */ Item::Item(THD *thd, Item *item): + rsize(0), str_value(item->str_value), name(item->name), orig_name(item->orig_name), diff --git a/sql/item.h b/sql/item.h index 11b9460906e..18a81dcaa03 100644 --- a/sql/item.h +++ b/sql/item.h @@ -232,6 +232,21 @@ public: static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } static void *operator new(size_t size, MEM_ROOT *mem_root) { return (void*) alloc_root(mem_root, (uint) size); } + /* Special for SP local variable assignment - reusing slots */ + static void *operator new(size_t size, Item *reuse, uint *rsize) + { + if (reuse && size <= reuse->rsize) + { + reuse->cleanup(); + TRASH((void *)reuse, size); + if (rsize) + (*rsize)= reuse->rsize; + return (void *)reuse; + } + if (rsize) + (*rsize)= size; + return (void *)sql_alloc((uint)size); + } static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} @@ -247,6 +262,9 @@ public: enum traverse_order { POSTFIX, PREFIX }; + /* Reuse size, only used by SP local variable assignment, otherwize 0 */ + uint rsize; + /* str_values's main purpose is to be used to cache the value in save_in_field diff --git a/sql/sp_head.cc b/sql/sp_head.cc index ca2ec6d0acf..988345694b2 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -131,10 +131,12 @@ sp_prepare_func_item(THD* thd, Item **it_addr) ** if nothing else. */ Item * -sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) +sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, + Item *reuse) { DBUG_ENTER("sp_eval_func_item"); Item *it= sp_prepare_func_item(thd, it_addr); + uint rsize; DBUG_PRINT("info", ("type: %d", type)); if (!it) @@ -144,7 +146,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) /* QQ How do we do this? Is there some better way? */ if (type == MYSQL_TYPE_NULL) - it= new Item_null(); + it= new(reuse, &rsize) Item_null(); else { switch (sp_map_result_type(type)) { @@ -155,12 +157,12 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) if (it->null_value) { DBUG_PRINT("info", ("INT_RESULT: null")); - it= new Item_null(); + it= new(reuse, &rsize) Item_null(); } else { DBUG_PRINT("info", ("INT_RESULT: %d", i)); - it= new Item_int(i); + it= new(reuse, &rsize) Item_int(i); } break; } @@ -171,7 +173,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) if (it->null_value) { DBUG_PRINT("info", ("REAL_RESULT: null")); - it= new Item_null(); + it= new(reuse, &rsize) Item_null(); } else { @@ -180,7 +182,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) uint8 decimals= it->decimals; uint32 max_length= it->max_length; DBUG_PRINT("info", ("REAL_RESULT: %g", d)); - it= new Item_float(d); + it= new(reuse, &rsize) Item_float(d); it->decimals= decimals; it->max_length= max_length; } @@ -190,9 +192,9 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) { my_decimal value, *val= it->val_decimal(&value); if (it->null_value) - it= new Item_null(); + it= new(reuse, &rsize) Item_null(); else - it= new Item_decimal(val); + it= new(reuse, &rsize) Item_decimal(val); #ifndef DBUG_OFF char dbug_buff[DECIMAL_MAX_STR_LENGTH+1]; DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val))); @@ -208,14 +210,16 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) if (it->null_value) { DBUG_PRINT("info", ("default result: null")); - it= new Item_null(); + it= new(reuse, &rsize) Item_null(); } else { DBUG_PRINT("info",("default result: %*s", s->length(), s->c_ptr_quick())); - it= new Item_string(thd->strmake(s->ptr(), s->length()), - s->length(), it->collation.collation); + it= new(reuse, &rsize) Item_string(thd->strmake(s->ptr(), + s->length()), + s->length(), + it->collation.collation); } break; } @@ -224,6 +228,7 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) DBUG_ASSERT(0); } } + it->rsize= rsize; DBUG_RETURN(it); } @@ -708,7 +713,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) for (i= 0 ; i < params && i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); - Item *it= sp_eval_func_item(thd, argp++, pvar->type); + Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL); if (it) nctx->push_item(it); @@ -823,7 +828,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) } else { - Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type); + Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL); if (it2) nctx->push_item(it2); // IN or INOUT @@ -1466,19 +1471,9 @@ sp_instr_set::execute(THD *thd, uint *nextp) int sp_instr_set::exec_core(THD *thd, uint *nextp) { - Item *it; - int res; + int res= thd->spcont->set_item_eval(thd, m_offset, &m_value, m_type); - it= sp_eval_func_item(thd, &m_value, m_type); - if (! it) - res= -1; - else - { - res= 0; - thd->spcont->set_item(m_offset, it); - } *nextp = m_ip+1; - return res; } @@ -1715,7 +1710,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) Item *it; int res; - it= sp_eval_func_item(thd, &m_value, m_type); + it= sp_eval_func_item(thd, &m_value, m_type, NULL); if (! it) res= -1; else diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 672491a97f2..49ead5d1585 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -40,19 +40,39 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax) m_saved.empty(); } + int -sp_rcontext::set_item_eval(uint idx, Item **item_addr, enum_field_types type) +sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr, + enum_field_types type) { - extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type); - Item *it= sp_eval_func_item(current_thd, item_addr, type); + extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type, + Item *reuse); + Item *it; + Item *reuse_it; + Item *old_item_next; + Item *old_free_list= thd->free_list; + int res; + LINT_INIT(old_item_next); + if ((reuse_it= get_item(idx))) + old_item_next= reuse_it->next; + it= sp_eval_func_item(thd, item_addr, type, reuse_it); if (! it) - return -1; + res= -1; else { + res= 0; + if (reuse_it && it == reuse_it) + { + // A reused item slot, where the constructor put it in the free_list, + // so we have to restore the list. + thd->free_list= old_free_list; + it->next= old_item_next; + } set_item(idx, it); - return 0; } + + return res; } bool @@ -111,7 +131,10 @@ void sp_rcontext::save_variables(uint fp) { while (fp < m_count) - m_saved.push_front(m_frame[fp++]); + { + m_saved.push_front(m_frame[fp]); + m_frame[fp++]= NULL; // Prevent reuse + } } void @@ -230,7 +253,12 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars) for (fldcount= 0 ; (pv= li++) ; fldcount++) { Item *it; + Item *reuse; + uint rsize; + Item *old_item_next; + Item *old_free_list= thd->free_list; const char *s; + LINT_INIT(old_item_next); if (fldcount >= m_prot->get_field_count()) { @@ -238,9 +266,13 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars) ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0)); return -1; } + + if ((reuse= thd->spcont->get_item(pv->offset))) + old_item_next= reuse->next; + s= row[fldcount]; if (!s) - it= new Item_null(); + it= new(reuse, &rsize) Item_null(); else { /* @@ -255,23 +287,32 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars) len= (*next -s)-1; switch (sp_map_result_type(pv->type)) { case INT_RESULT: - it= new Item_int(s); + it= new(reuse, &rsize) Item_int(s); break; case REAL_RESULT: - it= new Item_float(s, len); + it= new(reuse, &rsize) Item_float(s, len); break; case DECIMAL_RESULT: - it= new Item_decimal(s, len, thd->db_charset); + it= new(reuse, &rsize) Item_decimal(s, len, thd->db_charset); break; case STRING_RESULT: /* TODO: Document why we do an extra copy of the string 's' here */ - it= new Item_string(thd->strmake(s, len), len, thd->db_charset); + it= new(reuse, &rsize) Item_string(thd->strmake(s, len), len, + thd->db_charset); break; case ROW_RESULT: default: DBUG_ASSERT(0); } } + it->rsize= rsize; + if (reuse && it == reuse) + { + // A reused item slot, where the constructor put it in the free_list, + // so we have to restore the list. + thd->free_list= old_free_list; + it->next= old_item_next; + } thd->spcont->set_item(pv->offset, it); } if (fldcount < m_prot->get_field_count()) diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index c132032e32c..417c50d0f0f 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -62,19 +62,19 @@ class sp_rcontext : public Sql_alloc push_item(Item *i) { if (m_count < m_fsize) - m_frame[m_count++] = i; + m_frame[m_count++]= i; } inline void set_item(uint idx, Item *i) { if (idx < m_count) - m_frame[idx] = i; + m_frame[idx]= i; } /* Returns 0 on success, -1 on (eval) failure */ int - set_item_eval(uint idx, Item **i, enum_field_types type); + set_item_eval(THD *thd, uint idx, Item **i, enum_field_types type); inline Item * get_item(uint idx) @@ -82,7 +82,6 @@ class sp_rcontext : public Sql_alloc return m_frame[idx]; } - inline Item ** get_item_addr(uint idx) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2d5c4722164..2a500610479 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1746,7 +1746,8 @@ bool select_dumpvar::send_data(List<Item> &items) { if ((yy=var_li++)) { - if (thd->spcont->set_item_eval(yy->get_offset(), it.ref(), zz->type)) + if (thd->spcont->set_item_eval(current_thd, + yy->get_offset(), it.ref(), zz->type)) DBUG_RETURN(1); } } |