MDEV-32013 Add Field::val_lex_string_strmake()

There are two functions to extract a Field::val_str() value
as a LEX_STRING or LEX_CSTRING pointing to the data allocated on a MEM_ROOT:

  char *get_field(MEM_ROOT *mem, Field *field);
  bool get_field(MEM_ROOT *mem, Field *field, class String *res);

The first function requires strlen() calls to make a LEX_CSTRING/LEX_STRING.
The second function requires a redundant String buffer,
which is used only as a temporary proxy value pointing to a MEM_ROOT fragment
(and does not use any String dynamic allocation methods).

This patch add a native way to extract a Field::val_str() value
as a LEX_STRING or LEX_CSTRING pointing to a MEM_ROOT fragment.
It helps to remove redundant strlen() calls and redundant String buffers.

- Adding a new method:

    LEX_STRING Field::val_lex_string_strmake(MEM_ROOT *mem);

- Reusing the new method Field::val_lex_string_strmake() in;

    bool get_field(MEM_ROOT *mem, Field *field, String *res);

  Also, moving it from table.cc to a static function in sql_help.cc.
  It is used in sql_help.cc only, and we don't want it to be reused
  in other parts of the code (to avoid redundant String buffers).

- Reusing the new method Field::val_lex_string_strmake() in this function:

    char *get_field(MEM_ROOT *mem, Field *field);

- Replacing get_field() to Field::val_lex_string_strmake() in these files:

    sql_plugin.cc  (redundant String buffers were removed)
    sql_udf.cc     (redundant strlen() calls were removed)

Note, this function:

   char *get_field(MEM_ROOT *mem, Field *field);

is still used in a number of files:

   event_data_objects.cc
   event_db_repository.cc
   sql_acl.cc
   sql_servers.cc

These remaining calls will be removed by separate patches,
and get_field() will be removed after that.
This commit is contained in:
Alexander Barkov 2023-08-25 16:06:34 +04:00
parent 781ec16bd9
commit e0949cd6f0
7 changed files with 65 additions and 51 deletions

View file

@ -11380,6 +11380,15 @@ void Field::register_field_in_read_map()
}
LEX_STRING Field::val_lex_string_strmake(MEM_ROOT *mem)
{
StringBuffer<MAX_FIELD_WIDTH> str;
val_str(&str);
char *to= strmake_root(mem, str.ptr(), str.length());
return to ? LEX_STRING{to, str.length()} : LEX_STRING{NULL, 0};
}
bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
{
StringBuffer<MAX_FIELD_WIDTH> str;

View file

@ -1055,6 +1055,20 @@ public:
return to->copy((const char *) ptr, pack_length());
}
String *val_int_as_str(String *val_buffer, bool unsigned_flag);
/*
Copy the Field::val_str() value to MEM_ROOT as a 0x00-teminated string.
@param mem_root The memory root to put the value to.
@returns {NULL,0} in case of EOM, or the field value otherwise.
Only one 0x00 terminating byte is put in the end, even in case
of complex character sets like UCS2/UTF16/UTF32.
This is OK, since this method is used to read system tables,
which are in utf8.
*/
LEX_STRING val_lex_string_strmake(MEM_ROOT *mem_root);
/*
Return the field value as a LEX_CSTRING, without padding to full length
(MODE_PAD_CHAR_TO_FULL_LENGTH is temporarily suppressed during the call).

View file

@ -69,6 +69,29 @@ enum enum_used_fields
};
/*
Allocate string field in MEM_ROOT and return it as String
SYNOPSIS
get_field()
mem MEM_ROOT for allocating
field Field for retrieving of string
res result String
*/
static void get_field(MEM_ROOT *mem, Field *field, String *res)
{
THD *thd= field->get_thd();
Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
LEX_STRING ls= field->val_lex_string_strmake(mem);
DBUG_ASSERT((!ls.str && !ls.length) || ls.str[ls.length] == '\0');
if (!ls.str)
res->length(0); // EOM
else
res->set((const char *) ls.str, ls.length, field->charset());
}
/*
Fill st_find_field structure with pointers to fields

View file

@ -1883,12 +1883,11 @@ static void plugin_load(MEM_ROOT *tmp_root)
while (!(error= read_record_info.read_record()))
{
DBUG_PRINT("info", ("init plugin record"));
String str_name, str_dl;
get_field(tmp_root, table->field[0], &str_name);
get_field(tmp_root, table->field[1], &str_dl);
LEX_CSTRING name= {str_name.ptr(), str_name.length()};
LEX_CSTRING dl= {str_dl.ptr(), str_dl.length()};
DBUG_ASSERT(new_thd == table->field[0]->get_thd());
DBUG_ASSERT(new_thd == table->field[1]->get_thd());
DBUG_ASSERT(!(new_thd->variables.sql_mode & MODE_PAD_CHAR_TO_FULL_LENGTH));
LEX_CSTRING name= table->field[0]->val_lex_string_strmake(tmp_root);
LEX_CSTRING dl= table->field[1]->val_lex_string_strmake(tmp_root);
if (!name.length || !dl.length)
continue;

View file

@ -208,10 +208,11 @@ void udf_init()
while (!(error= read_record_info.read_record()))
{
DBUG_PRINT("info",("init udf record"));
LEX_CSTRING name;
name.str=get_field(&mem, table->field[0]);
name.length = (uint) safe_strlen(name.str);
char *dl_name= get_field(&mem, table->field[2]);
DBUG_ASSERT(!(new_thd->variables.sql_mode & MODE_PAD_CHAR_TO_FULL_LENGTH));
DBUG_ASSERT(table->field[0]->get_thd() == new_thd);
DBUG_ASSERT(table->field[2]->get_thd() == new_thd);
LEX_CSTRING name= table->field[0]->val_lex_string_strmake(&mem);
LEX_CSTRING dl_name= table->field[2]->val_lex_string_strmake(&mem);
bool new_dl=0;
Item_udftype udftype=UDFTYPE_FUNCTION;
if (table->s->fields >= 4) // New func table
@ -224,7 +225,8 @@ void udf_init()
On windows we must check both FN_LIBCHAR and '/'.
*/
if (!name.str || !dl_name || check_valid_path(dl_name, strlen(dl_name)) ||
if (!name.length || !dl_name.length ||
check_valid_path(dl_name.str, dl_name.length) ||
check_string_char_length(&name, 0, NAME_CHAR_LEN,
system_charset_info, 1))
{
@ -234,7 +236,7 @@ void udf_init()
}
if (!(tmp= add_udf(&name,(Item_result) table->field[1]->val_int(),
dl_name, udftype)))
dl_name.str, udftype)))
{
sql_print_error("Can't alloc memory for udf function: '%.64s'", name.str);
continue;

View file

@ -5090,40 +5090,6 @@ rename_file_ext(const char * from,const char * to,const char * ext)
}
/*
Allocate string field in MEM_ROOT and return it as String
SYNOPSIS
get_field()
mem MEM_ROOT for allocating
field Field for retrieving of string
res result String
RETURN VALUES
1 string is empty
0 all ok
*/
bool get_field(MEM_ROOT *mem, Field *field, String *res)
{
const char *to;
StringBuffer<MAX_FIELD_WIDTH> str;
bool rc;
THD *thd= field->get_thd();
Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
field->val_str(&str);
if ((rc= !str.length() ||
!(to= strmake_root(mem, str.ptr(), str.length()))))
{
res->length(0);
return rc;
}
res->set(to, str.length(), field->charset());
return false;
}
/*
Allocate string field in MEM_ROOT and return it as NULL-terminated string
@ -5139,10 +5105,12 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res)
char *get_field(MEM_ROOT *mem, Field *field)
{
String str;
bool rc= get_field(mem, field, &str);
DBUG_ASSERT(rc || str.ptr()[str.length()] == '\0');
return rc ? NullS : (char *) str.ptr();
THD *thd= field->get_thd();
Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
LEX_STRING ls= field->val_lex_string_strmake(mem);
DBUG_ASSERT((!ls.str && !ls.length) || ls.str[ls.length] == '\0');
// Empty string "" is intentionally returned as NullS
return ls.length == 0 ? NullS : ls.str;
}
/*

View file

@ -3404,7 +3404,6 @@ bool check_period_name(const char *name);
bool check_table_name(const char *name, size_t length, bool check_for_path_chars);
int rename_file_ext(const char * from,const char * to,const char * ext);
char *get_field(MEM_ROOT *mem, Field *field);
bool get_field(MEM_ROOT *mem, Field *field, class String *res);
bool validate_comment_length(THD *thd, LEX_CSTRING *comment, size_t max_len,
uint err_code, const char *name);