1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

Tree<> - a typesafe wrapper for TREE

This commit is contained in:
Sergei Golubchik
2026-06-10 17:47:32 +02:00
parent 005de83022
commit 4c0c4bbfcd
8 changed files with 244 additions and 170 deletions

View File

@@ -1,5 +1,6 @@
/*
Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2010, 2026, MariaDB plc.
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
@@ -45,7 +46,6 @@ int compare_double2(void *, const void *s_, const void *t_)
{
const double *s= static_cast<const double*>(s_);
const double *t= static_cast<const double*>(t_);
return compare_double(s,t);
}
@@ -285,7 +285,7 @@ bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num)
{
if (((longlong) info->ullval) < 0)
return 0; // Impossible to store as a negative number
ev_info->llval = -(longlong) MY_MAX((ulonglong) -ev_info->llval,
ev_info->llval = -(longlong) MY_MAX((ulonglong) -ev_info->llval,
info->ullval);
ev_info->min_dval = (double) -MY_MAX(-ev_info->min_dval, info->dval);
}
@@ -300,13 +300,6 @@ bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num)
} // get_ev_num_info
int free_string(void* str, TREE_FREE, void*)
{
((String*)str)->free();
return 0;
}
void field_str::add()
{
char buff[MAX_FIELD_WIDTH], *ptr;
@@ -371,22 +364,22 @@ void field_str::add()
{
if (res != &s)
s.copy(*res);
if (!tree_search(&tree, (void*) &s, tree.custom_arg)) // If not in tree
if (!tree.find(s)) // If not in tree
{
s.copy(); // slow, when SAFE_MALLOC is in use
if (!tree_insert(&tree, (void*) &s, 0, tree.custom_arg))
if (tree.insert(s))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree, 0);
room_in_tree = 0; // Remove tree, out of RAM ?
tree.clear();
}
else
{
bzero((char*) &s, sizeof(s)); // Let tree handle free of this
if ((treemem += length) > pc->max_treemem)
{
room_in_tree = 0; // Remove tree, too big tree
delete_tree(&tree, 0);
}
s.release(); // Let tree handle free of this
if ((treemem += length) > pc->max_treemem)
{
room_in_tree = 0; // Remove tree, too big tree
tree.clear();
}
}
}
}
@@ -402,7 +395,6 @@ void field_real::add()
char buff[MAX_FIELD_WIDTH], *ptr, *end;
double num= item->val_real();
uint length, zero_count, decs;
TREE_ELEMENT *element;
if (item->null_value)
{
@@ -437,19 +429,15 @@ void field_real::add()
if (room_in_tree)
{
if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
if (tree.insert(num))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree, 0);
tree.clear();
}
/*
if element->count == 1, this element can be found only once from tree
if element->count == 2, or more, this element is already in tree
*/
else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
else if ((tree_elements= tree.elements()) > pc->max_tree_elements)
{
room_in_tree = 0; // Remove tree, too many elements
delete_tree(&tree, 0);
tree.clear();
}
}
@@ -481,7 +469,6 @@ void field_decimal::add()
/*TODO - remove rounding stuff after decimal_div returns proper frac */
VDec vdec(item);
uint length;
TREE_ELEMENT *element;
if (vdec.is_null())
{
@@ -499,21 +486,17 @@ void field_decimal::add()
if (room_in_tree)
{
uchar buf[DECIMAL_MAX_FIELD_SIZE];
dec.to_binary(buf, item->max_length, item->decimals);
if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg)))
DecimalKey key;
dec.to_binary(key.data, item->max_length, item->decimals);
if (tree.insert(key))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree, 0);
tree.clear();
}
/*
if element->count == 1, this element can be found only once from tree
if element->count == 2, or more, this element is already in tree
*/
else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
else if ((tree_elements= tree.elements()) > pc->max_tree_elements)
{
room_in_tree = 0; // Remove tree, too many elements
delete_tree(&tree, 0);
tree.clear();
}
}
@@ -556,7 +539,6 @@ void field_longlong::add()
longlong numlong = item->val_int();
double num = (double) numlong;
uint length = (uint) (longlong10_to_str(numlong, buff, -10) - buff);
TREE_ELEMENT *element;
if (item->null_value)
{
@@ -568,19 +550,15 @@ void field_longlong::add()
if (room_in_tree)
{
if (!(element = tree_insert(&tree, (void*) &numlong, 0, tree.custom_arg)))
if (tree.insert(numlong))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree, 0);
tree.clear();
}
/*
if element->count == 1, this element can be found only once from tree
if element->count == 2, or more, this element is already in tree
*/
else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
else if ((tree_elements= tree.elements()) > pc->max_tree_elements)
{
room_in_tree = 0; // Remove tree, too many elements
delete_tree(&tree, 0);
tree.clear();
}
}
@@ -614,7 +592,6 @@ void field_ulonglong::add()
ulonglong numlong = item->val_int();
double num= (double) numlong;
uint length = (uint) (longlong10_to_str(numlong, buff, 10) - buff);
TREE_ELEMENT *element;
if (item->null_value)
{
@@ -626,19 +603,15 @@ void field_ulonglong::add()
if (room_in_tree)
{
if (!(element = tree_insert(&tree, (void*) &numlong, 0, tree.custom_arg)))
if (tree.insert(numlong))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree, 0);
tree.clear();
}
/*
if element->count == 1, this element can be found only once from tree
if element->count == 2, or more, this element is already in tree
*/
else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
else if ((tree_elements= tree.elements()) > pc->max_tree_elements)
{
room_in_tree = 0; // Remove tree, too many elements
delete_tree(&tree, 0);
tree.clear();
}
}
@@ -683,11 +656,9 @@ int analyse::send_row(List<Item> & /* field_list */)
int analyse::end_of_records()
{
field_info **f = f_info;
char buff[MAX_FIELD_WIDTH];
String *res, s_min(buff, sizeof(buff),&my_charset_bin),
s_max(buff, sizeof(buff),&my_charset_bin),
ans(buff, sizeof(buff),&my_charset_bin);
StringBuffer<MAX_FIELD_WIDTH> s;
StringBuffer<NAME_LEN> name;
String *res;
for (; f != f_end; f++)
{
@@ -708,20 +679,20 @@ int analyse::end_of_records()
else
{
func_items[1]->null_value = 0;
res = (*f)->get_min_arg(&s_min);
res = (*f)->get_min_arg(&s);
func_items[1]->set(res->ptr(), res->length(), res->charset());
func_items[2]->null_value = 0;
res = (*f)->get_max_arg(&s_max);
res = (*f)->get_max_arg(&s);
func_items[2]->set(res->ptr(), res->length(), res->charset());
}
func_items[3]->set((longlong) (*f)->min_length);
func_items[4]->set((longlong) (*f)->max_length);
func_items[5]->set((longlong) (*f)->empty);
func_items[6]->set((longlong) (*f)->nulls);
res = (*f)->avg(&s_max, rows);
res = (*f)->avg(&s, rows);
func_items[7]->set(res->ptr(), res->length(), res->charset());
func_items[8]->null_value = 0;
res = (*f)->std(&s_max, rows);
res = (*f)->std(&s, rows);
if (!res)
func_items[8]->null_value = 1;
else
@@ -730,17 +701,17 @@ int analyse::end_of_records()
count the dots, quotas, etc. in (ENUM("a","b","c"...))
If tree has been removed, don't suggest ENUM.
treemem is used to measure the size of tree for strings,
tree_elements is used to count the elements
tree_elements is used to count the elements for numerics
max_treemem tells how long the string starting from ENUM("... and
ending to ..") shall at maximum be. If case is about numbers,
max_tree_elements will tell the length of the above, now
every number is considered as length 1
*/
if (((*f)->treemem || (*f)->tree_elements) &&
(*f)->tree.elements_in_tree &&
(*f)->tree_size() &&
(((*f)->treemem ? max_treemem : max_tree_elements) >
(((*f)->treemem ? (*f)->treemem : (*f)->tree_elements) +
((*f)->tree.elements_in_tree * 3 - 1 + 6))))
((*f)->tree_size() * 3 - 1 + 6))))
{
char tmp[331]; //331, because one double prec. num. can be this long
String tmp_str(tmp, sizeof(tmp),&my_charset_bin);
@@ -751,8 +722,7 @@ int analyse::end_of_records()
tree_info.item = (*f)->item;
tmp_str.set(STRING_WITH_LEN("ENUM("),&my_charset_bin);
tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info,
left_root_right);
(*f)->walk_tree(&tree_info);
tmp_str.append(')');
if (!(*f)->nulls)
@@ -764,46 +734,46 @@ int analyse::end_of_records()
continue;
}
ans.length(0);
s.length(0);
if (!(*f)->treemem && !(*f)->tree_elements)
ans.append(STRING_WITH_LEN("CHAR(0)"));
s.append(STRING_WITH_LEN("CHAR(0)"));
else if ((*f)->item->type() == Item::FIELD_ITEM)
{
switch (((Item_field*) (*f)->item)->field->real_type())
{
case MYSQL_TYPE_TIMESTAMP:
ans.append(STRING_WITH_LEN("TIMESTAMP"));
s.append(STRING_WITH_LEN("TIMESTAMP"));
break;
case MYSQL_TYPE_DATETIME:
ans.append(STRING_WITH_LEN("DATETIME"));
s.append(STRING_WITH_LEN("DATETIME"));
break;
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_NEWDATE:
ans.append(STRING_WITH_LEN("DATE"));
s.append(STRING_WITH_LEN("DATE"));
break;
case MYSQL_TYPE_SET:
ans.append(STRING_WITH_LEN("SET"));
s.append(STRING_WITH_LEN("SET"));
break;
case MYSQL_TYPE_YEAR:
ans.append(STRING_WITH_LEN("YEAR"));
s.append(STRING_WITH_LEN("YEAR"));
break;
case MYSQL_TYPE_TIME:
ans.append(STRING_WITH_LEN("TIME"));
s.append(STRING_WITH_LEN("TIME"));
break;
case MYSQL_TYPE_DECIMAL:
ans.append(STRING_WITH_LEN("DECIMAL"));
s.append(STRING_WITH_LEN("DECIMAL"));
// if item is FIELD_ITEM, it _must_be_ Field_num in this case
if (((Field_num*) ((Item_field*) (*f)->item)->field)->zerofill)
ans.append(STRING_WITH_LEN(" ZEROFILL"));
s.append(STRING_WITH_LEN(" ZEROFILL"));
break;
default:
(*f)->get_opt_type(&ans, rows);
(*f)->get_opt_type(&s, rows);
break;
}
}
if (!(*f)->nulls)
ans.append(STRING_WITH_LEN(" NOT NULL"));
func_items[9]->set(ans.ptr(), ans.length(), ans.charset());
s.append(STRING_WITH_LEN(" NOT NULL"));
func_items[9]->set(s.ptr(), s.length(), s.charset());
if (result->send_data(result_fields) > 0)
return -1;
}
@@ -1082,26 +1052,27 @@ String *field_decimal::std(String *s, ha_rows rows)
}
int collect_string(void *element_, element_count, void *info_)
int collect_string(const String &element, element_count, TREE_INFO *info)
{
String *element= static_cast<String*>(element_);
TREE_INFO *info= static_cast<TREE_INFO*>(info_);
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
if (info->str->append_for_single_quote(element))
if (info->str->append_for_single_quote(&element))
return 1;
info->str->append('\'');
return 0;
} // collect_string
int collect_real(void *element_, element_count, void *info_)
void field_str::walk_tree(TREE_INFO *info)
{
tree.walk(collect_string, info);
}
int collect_real(const double &element, element_count, TREE_INFO *info)
{
double *element= static_cast<double*>(element_);
TREE_INFO *info= static_cast<TREE_INFO*>(info_);
char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff),current_thd->charset());
@@ -1110,17 +1081,20 @@ int collect_real(void *element_, element_count, void *info_)
else
info->found = 1;
info->str->append('\'');
s.set_real(*element, info->item->decimals, current_thd->charset());
s.set_real(element, info->item->decimals, current_thd->charset());
info->str->append(s);
info->str->append('\'');
return 0;
} // collect_real
int collect_decimal(void *element_, element_count count, void *info_)
void field_real::walk_tree(TREE_INFO *info)
{
tree.walk(collect_real, info);
}
int collect_decimal(const DecimalKey &key, element_count, TREE_INFO *info)
{
uchar *element= static_cast<uchar*>(element_);
TREE_INFO *info= static_cast<TREE_INFO*>(info_);
char buff[DECIMAL_MAX_STR_LENGTH];
String s(buff, sizeof(buff),&my_charset_bin);
@@ -1128,7 +1102,7 @@ int collect_decimal(void *element_, element_count count, void *info_)
info->str->append(',');
else
info->found = 1;
my_decimal dec(element, info->item->max_length, info->item->decimals);
my_decimal dec(key.data, info->item->max_length, info->item->decimals);
info->str->append('\'');
dec.to_string_native(&s, 0, 0, '0');
info->str->append(s);
@@ -1136,11 +1110,14 @@ int collect_decimal(void *element_, element_count count, void *info_)
return 0;
}
int collect_longlong(void *element_, element_count, void *info_)
void field_decimal::walk_tree(TREE_INFO *info)
{
tree.walk(collect_decimal, info);
}
int collect_longlong(const longlong &element, element_count, TREE_INFO *info)
{
longlong *element= static_cast<longlong*>(element_);
TREE_INFO *info= static_cast<TREE_INFO*>(info_);
char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff),&my_charset_bin);
@@ -1149,17 +1126,20 @@ int collect_longlong(void *element_, element_count, void *info_)
else
info->found = 1;
info->str->append('\'');
s.set(*element, current_thd->charset());
s.set(element, current_thd->charset());
info->str->append(s);
info->str->append('\'');
return 0;
} // collect_longlong
int collect_ulonglong(void *element_, element_count, void *info_)
void field_longlong::walk_tree(TREE_INFO *info)
{
tree.walk(collect_longlong, info);
}
int collect_ulonglong(const ulonglong &element, element_count, TREE_INFO *info)
{
ulonglong *element= static_cast<ulonglong*>(element_);
TREE_INFO *info= static_cast<TREE_INFO*>(info_);
char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff),&my_charset_bin);
@@ -1168,12 +1148,17 @@ int collect_ulonglong(void *element_, element_count, void *info_)
else
info->found = 1;
info->str->append('\'');
s.set(*element, current_thd->charset());
s.set(element, current_thd->charset());
info->str->append(s);
info->str->append('\'');
return 0;
} // collect_ulonglong
void field_ulonglong::walk_tree(TREE_INFO *info)
{
tree.walk(collect_ulonglong, info);
}
bool analyse::change_columns(THD *thd, List<Item> &field_list)
{

View File

@@ -1,7 +1,8 @@
#ifndef SQL_ANALYSE_INCLUDED
#define SQL_ANALYSE_INCLUDED
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates.
Copyright (c) 2010, 2026, MariaDB plc.
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
@@ -20,6 +21,7 @@
/* Analyse database */
#include "procedure.h" /* Procedure */
#include "sql_tree.h"
#define my_thd_charset default_charset_info
@@ -61,7 +63,12 @@ int compare_ulonglong2(void *, const void *s, const void *t);
int compare_decimal2(void *len, const void *s, const void *t);
Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result,
List<Item> &field_list);
int free_string(void* str, TREE_FREE, void*);
struct DecimalKey
{
uchar data[DECIMAL_MAX_FIELD_SIZE];
};
class analyse;
class field_info :public Sql_alloc
@@ -70,7 +77,6 @@ protected:
ulong treemem, tree_elements, empty, nulls, min_length, max_length;
uint room_in_tree;
bool found;
TREE tree;
Item *item;
analyse *pc;
@@ -79,19 +85,20 @@ public:
nulls(0), min_length(0), max_length(0), room_in_tree(1),
found(0),item(a), pc(b) {};
virtual ~field_info() { delete_tree(&tree, 0); }
virtual ~field_info() = default;
virtual void add() = 0;
virtual void get_opt_type(String*, ha_rows) = 0;
virtual String *get_min_arg(String *) = 0;
virtual String *get_max_arg(String *) = 0;
virtual String *avg(String*, ha_rows) = 0;
virtual String *std(String*, ha_rows) = 0;
virtual tree_walk_action collect_enum() = 0;
virtual void walk_tree(TREE_INFO *) = 0;
virtual uint tree_size() const = 0;
virtual uint decimals() { return 0; }
friend class analyse;
};
int collect_string(void *element, element_count count, void *info);
int collect_string(const String &element, element_count count, TREE_INFO &info);
int sortcmp2(void *, const void *a, const void *b);
@@ -103,17 +110,16 @@ class field_str :public field_info
can_be_still_num;
NUM_INFO num_info;
EV_NUM_INFO ev_num_info;
Tree<String> tree;
public:
field_str(Item* a, analyse* b) :field_info(a,b),
field_str(Item* a, analyse* b) :field_info(a,b),
min_arg("",0,default_charset_info),
max_arg("",0,default_charset_info), sum(0),
must_be_blob(0), was_zero_fill(0),
was_maybe_zerofill(0), can_be_still_num(1)
{
init_tree(&tree, 0, 0, sizeof(String), sortcmp2, free_string, NULL,
MYF(MY_THREAD_SPECIFIC));
};
was_maybe_zerofill(0), can_be_still_num(1),
tree(sortcmp2, nullptr, MYF(MY_THREAD_SPECIFIC))
{};
void add() override;
void get_opt_type(String*, ha_rows) override;
@@ -130,17 +136,18 @@ public:
DEC_IN_AVG,my_thd_charset);
return s;
}
friend int collect_string(String *element, element_count count,
TREE_INFO *info);
tree_walk_action collect_enum() override
{ return collect_string; }
void walk_tree(TREE_INFO *info) override;
uint tree_size() const override { return tree.elements(); }
friend int collect_string(const String &element, element_count count,
TREE_INFO &info);
String *std(String *s __attribute__((unused)),
ha_rows rows __attribute__((unused))) override
{ return (String*) 0; }
};
int collect_decimal(void *element, element_count count, void *info);
int collect_decimal(const DecimalKey &element, element_count count,
TREE_INFO &info);
class field_decimal :public field_info
{
@@ -148,42 +155,40 @@ class field_decimal :public field_info
my_decimal sum[2], sum_sqr[2];
int cur_sum;
int bin_size;
Tree<DecimalKey, int> tree;
public:
field_decimal(Item* a, analyse* b) :field_info(a,b)
{
bin_size= my_decimal_get_binary_size(a->max_length, a->decimals);
init_tree(&tree, 0, 0, bin_size, compare_decimal2, 0, (void *) &bin_size,
MYF(MY_THREAD_SPECIFIC));
};
field_decimal(Item* a, analyse* b) :field_info(a,b),
bin_size((int) my_decimal_get_binary_size(a->max_length, a->decimals)),
tree(compare_decimal2, &bin_size, MYF(MY_THREAD_SPECIFIC))
{};
void add() override;
void get_opt_type(String*, ha_rows) override;
String *get_min_arg(String *) override;
String *get_max_arg(String *) override;
String *avg(String *s, ha_rows rows) override;
friend int collect_decimal(uchar *element, element_count count,
TREE_INFO *info);
tree_walk_action collect_enum() override
{ return collect_decimal; }
friend int collect_decimal(const DecimalKey &element, element_count count,
TREE_INFO &info);
void walk_tree(TREE_INFO *info) override;
uint tree_size() const override { return tree.elements(); }
String *std(String *s, ha_rows rows) override;
};
int collect_real(void *element, element_count count, void *info);
int collect_real(const double &element, element_count count, TREE_INFO &info);
class field_real: public field_info
{
double min_arg, max_arg;
double sum, sum_sqr;
uint max_notzero_dec_len;
Tree<double> tree;
public:
field_real(Item* a, analyse* b) :field_info(a,b),
min_arg(0), max_arg(0), sum(0), sum_sqr(0), max_notzero_dec_len(0)
{
init_tree(&tree, 0, 0, sizeof(double), compare_double2, NULL, NULL,
MYF(MY_THREAD_SPECIFIC));
}
min_arg(0), max_arg(0), sum(0), sum_sqr(0), max_notzero_dec_len(0),
tree(compare_double2, nullptr, MYF(MY_THREAD_SPECIFIC))
{}
void add() override;
void get_opt_type(String*, ha_rows) override;
@@ -219,26 +224,26 @@ public:
return s;
}
uint decimals() override { return item->decimals; }
friend int collect_real(double *element, element_count count,
TREE_INFO *info);
tree_walk_action collect_enum() override
{ return collect_real;}
void walk_tree(TREE_INFO *info) override;
uint tree_size() const override { return tree.elements(); }
friend int collect_real(const double &element, element_count count,
TREE_INFO &info);
};
int collect_longlong(void *element, element_count count, void *info);
int collect_longlong(const longlong &element, element_count count,
TREE_INFO &info);
class field_longlong: public field_info
{
longlong min_arg, max_arg;
double sum, sum_sqr;
Tree<longlong> tree;
public:
field_longlong(Item* a, analyse* b) :field_info(a,b),
min_arg(0), max_arg(0), sum(0), sum_sqr(0.0)
{
init_tree(&tree, 0, 0, sizeof(longlong), compare_longlong2, NULL, NULL,
MYF(MY_THREAD_SPECIFIC));
}
field_longlong(Item* a, analyse* b) :field_info(a,b),
min_arg(0), max_arg(0), sum(0), sum_sqr(0.0),
tree(compare_longlong2, nullptr, MYF(MY_THREAD_SPECIFIC))
{}
void add() override;
void get_opt_type(String*, ha_rows) override;
@@ -265,26 +270,26 @@ public:
}
return s;
}
friend int collect_longlong(longlong *element, element_count count,
TREE_INFO *info);
tree_walk_action collect_enum() override
{ return collect_longlong;}
void walk_tree(TREE_INFO *info) override;
uint tree_size() const override { return tree.elements(); }
friend int collect_longlong(const longlong &element, element_count count,
TREE_INFO &info);
};
int collect_ulonglong(void *element, element_count count, void *info);
int collect_ulonglong(const ulonglong &element, element_count count,
TREE_INFO &info);
class field_ulonglong: public field_info
{
ulonglong min_arg, max_arg;
double sum, sum_sqr;
Tree<ulonglong> tree;
public:
field_ulonglong(Item* a, analyse * b) :field_info(a,b),
min_arg(0), max_arg(0), sum(0),sum_sqr(0)
{
init_tree(&tree, 0, 0, sizeof(ulonglong), compare_ulonglong2, NULL, NULL,
MYF(MY_THREAD_SPECIFIC));
}
min_arg(0), max_arg(0), sum(0),sum_sqr(0),
tree(compare_ulonglong2, nullptr, MYF(MY_THREAD_SPECIFIC))
{}
void add() override;
void get_opt_type(String*, ha_rows) override;
String *get_min_arg(String *s) override { s->set(min_arg,my_thd_charset); return s; }
@@ -312,10 +317,10 @@ public:
}
return s;
}
friend int collect_ulonglong(ulonglong *element, element_count count,
TREE_INFO *info);
tree_walk_action collect_enum() override
{ return collect_ulonglong; }
void walk_tree(TREE_INFO *info) override;
uint tree_size() const override { return tree.elements(); }
friend int collect_ulonglong(const ulonglong &element, element_count count,
TREE_INFO &info);
};

89
sql/sql_tree.h Normal file
View File

@@ -0,0 +1,89 @@
#ifndef SQL_TREE_INCLUDED
#define SQL_TREE_INCLUDED
/*
Copyright (c) 2026, MariaDB plc
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 <my_tree.h>
/*
Type-safe wrapper around the C TREE red-black tree.
*/
template<typename T, typename Param=void>
class Tree
{
TREE m_tree;
static int free_shim(void *elem, TREE_FREE action, void *)
{
if (action == free_free)
static_cast<T *>(elem)->~T();
return 0;
}
template<typename Ctx>
struct walk_arg
{
int (*fn)(const T &, element_count, Ctx *);
Ctx *ctx;
};
template<typename Ctx>
static int call_shim(void *elem, element_count cnt, void *arg_)
{
auto *arg= static_cast<walk_arg<Ctx> *>(arg_);
return arg->fn(*static_cast<const T *>(elem), cnt, arg->ctx);
}
public:
explicit Tree(qsort_cmp2 fn, Param *extra_arg= nullptr, myf flags= MYF(0))
{
init_tree(&m_tree, 0, 0, sizeof(T), fn, free_shim, (void*)extra_arg, flags);
}
~Tree() { delete_tree(&m_tree, 0); }
void clear() { delete_tree(&m_tree, 0); }
Tree(const Tree &)= delete;
Tree &operator=(const Tree &)= delete;
/* Insert val; returns true on OOM. Duplicate inserts increment the count. */
bool insert(const T &val)
{
return tree_insert(&m_tree, &val, 0, m_tree.custom_arg) == nullptr;
}
T *find(const T &key)
{
return static_cast<T *>(tree_search(&m_tree, &key, m_tree.custom_arg));
}
/*
Walk all elements in order, calling fn(const T &, element_count, Ctx &).
fn should return 0 to continue, non-zero to stop.
*/
template<typename Ctx>
int walk(int (*fn)(const T &, element_count, Ctx *), Ctx *ctx,
TREE_WALK dir= left_root_right)
{
walk_arg<Ctx> arg= {fn, ctx};
return tree_walk(&m_tree, call_shim<Ctx>, &arg, dir);
}
uint elements() const { return m_tree.elements_in_tree; }
};
#endif /* SQL_TREE_INCLUDED */

View File

@@ -377,7 +377,6 @@
#include "sql_priv.h"
#include "sql_servers.h" // FOREIGN_SERVER, get_server_by_name
#include "sql_class.h" // SSV
#include "sql_analyse.h" // append_escaped
#include <mysql/plugin.h>
#include "ha_federated.h"

View File

@@ -314,7 +314,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <mysql.h>
#include "ha_federatedx.h"
#include "sql_servers.h"
#include "sql_analyse.h" // append_escaped()
#include "sql_show.h" // append_identifier()
#include "tztime.h" // my_tz_find()
#include "sql_select.h"

View File

@@ -21,7 +21,6 @@
#include "probes_mysql.h"
#include "sql_class.h"
#include "sql_partition.h"
#include "sql_analyse.h"
#include "sql_base.h"
#include "tztime.h"
#include "errmsg.h"

View File

@@ -21,7 +21,6 @@
#include "probes_mysql.h"
#include "sql_class.h"
#include "sql_partition.h"
#include "sql_analyse.h"
#include "sql_base.h"
#include "tztime.h"
#include "sql_select.h"

View File

@@ -20,7 +20,6 @@
#include "sql_priv.h"
#include "probes_mysql.h"
#include "sql_class.h"
#include "sql_analyse.h"
#include "spd_db_include.h"
#include "spd_include.h"
#include "spd_malloc.h"