Understanding MySQL’s DYNAMIC_STRING: Structure, Initialization, and Manipulation
The article explains MySQL’s DYNAMIC_STRING structure, detailing its fields, how to initialize it with init_dynamic_string, and how functions like dynstr_append_mem, dynstr_trunc, dynstr_realloc, and dynstr_append_os_quoted manage dynamic resizing, truncation, and OS‑quote handling for safe string operations.
MySQL uses the DYNAMIC_STRING struct to store a mutable string together with metadata needed for efficient resizing. The struct is defined as:
typedef struct st_dynamic_string {
char *str; // pointer to the actual characters
size_t length; // current length of the string (excluding '\0')
size_t max_length; // total allocated buffer size
size_t alloc_increment; // allocation step size for growth
} DYNAMIC_STRING;During initialization, init_dynamic_string determines the initial buffer size based on the supplied initial string and the desired allocation increment. It allocates memory with my_malloc, copies the initial content if present, and records the length, maximum length, and increment values.
my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
size_t init_alloc, size_t alloc_increment) {
size_t length;
DBUG_ENTER("init_dynamic_string");
if (!alloc_increment) alloc_increment = 128;
length = 1;
if (init_str && (length = strlen(init_str) + 1) < init_alloc)
init_alloc = ((length + alloc_increment - 1) / alloc_increment) * alloc_increment;
if (!init_alloc) init_alloc = alloc_increment;
if (!(str->str = (char *)my_malloc(init_alloc, MYF(MY_WME))))
DBUG_RETURN(TRUE);
str->length = length - 1;
if (init_str)
memcpy(str->str, init_str, length);
str->max_length = init_alloc;
str->alloc_increment = alloc_increment;
DBUG_RETURN(FALSE);
}Appending data is handled by dynstr_append_mem. If the new total length would exceed max_length, the function calculates a new buffer size that is a multiple of alloc_increment, reallocates with my_realloc, and then copies the new bytes.
my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append, size_t length) {
char *new_ptr;
if (str->length + length >= str->max_length) {
size_t new_length = (str->length + length + str->alloc_increment) /
str->alloc_increment;
new_length *= str->alloc_increment;
if (!(new_ptr = (char *)my_realloc(str->str, new_length, MYF(MY_WME))))
return TRUE;
str->str = new_ptr;
str->max_length = new_length;
}
memcpy(str->str + str->length, append, length);
str->length += length;
str->str[str->length] = '\0';
return FALSE;
}Truncating a string simply reduces length and places a terminating null character at the new end:
my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n) {
str->length -= n;
str->str[str->length] = '\0';
return FALSE;
}When a larger increase is needed, dynstr_realloc expands the buffer to the next multiple of alloc_increment that can accommodate the additional size.
my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size) {
DBUG_ENTER("dynstr_realloc");
if (!additional_size) DBUG_RETURN(FALSE);
if (str->length + additional_size > str->max_length) {
str->max_length = ((str->length + additional_size + str->alloc_increment - 1) /
str->alloc_increment) * str->alloc_increment;
if (!(str->str = (char *)my_realloc(str->str, str->max_length, MYF(MY_WME))))
DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
}For building command‑line strings that need OS‑level quoting, dynstr_append_os_quoted concatenates arbitrary strings, escapes any single‑quote characters, surrounds the whole result in quotes, and appends it to a DYNAMIC_STRING. It uses a helper strcend to locate quote characters.
my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, ...) {
const char *quote_str = "'";
const uint quote_len = 1;
my_bool ret = TRUE;
va_list dirty_text;
ret &= dynstr_append_mem(str, quote_str, quote_len); // leading quote
va_start(dirty_text, append);
while (append != NullS) {
const char *cur_pos = append;
const char *next_pos;
while (*(next_pos = strcend(cur_pos, quote_str[0])) != '\0') {
ret &= dynstr_append_mem(str, cur_pos, (uint)(next_pos - cur_pos));
ret &= dynstr_append_mem(str, "\\", 1);
ret &= dynstr_append_mem(str, quote_str, quote_len);
cur_pos = next_pos + 1;
}
ret &= dynstr_append_mem(str, cur_pos, (uint)(next_pos - cur_pos));
append = va_arg(dirty_text, char *);
}
va_end(dirty_text);
ret &= dynstr_append_mem(str, quote_str, quote_len); // trailing quote
return ret;
}Overall, by encapsulating the current length, allocated capacity, and growth step, the DYNAMIC_STRING abstraction lets MySQL efficiently grow, shrink, and safely manipulate strings without manual bookkeeping, simplifying many internal operations such as building SQL statements or system commands.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
