~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
17
/* Functions to handle keys and fields in forms */
18
934.2.21 by Jay Pipes
Move Key stuff into key.cc and out of session.cc
19
#include "drizzled/server_includes.h"
20
#include "drizzled/table.h"
21
#include "drizzled/key.h"
22
#include "drizzled/field/blob.h"
1 by brian
clean slate
23
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
24
#include <string>
25
26
using namespace std;
27
1 by brian
clean slate
28
/*
29
  Search after a key that starts with 'field'
30
31
  SYNOPSIS
32
    find_ref_key()
33
    key			First key to check
34
    key_count		How many keys to check
35
    record		Start of record
36
    field		Field to search after
37
    key_length		On partial match, contains length of fields before
38
			field
39
    keypart             key part # of a field
40
41
  NOTES
42
   Used when calculating key for NEXT_NUMBER
43
44
  IMPLEMENTATION
45
    If no key starts with field test if field is part of some key. If we find
46
    one, then return first key and set key_length to the number of bytes
47
    preceding 'field'.
48
49
  RETURN
50
   -1  field is not part of the key
51
   #   Key part for key matching key.
52
       key_length is set to length of key before (not including) field
53
*/
54
482 by Brian Aker
Remove uint.
55
int find_ref_key(KEY *key, uint32_t key_count, unsigned char *record, Field *field,
56
                 uint32_t *key_length, uint32_t *keypart)
1 by brian
clean slate
57
{
58
  register int i;
59
  register KEY *key_info;
482 by Brian Aker
Remove uint.
60
  uint32_t fieldpos;
1 by brian
clean slate
61
62
  fieldpos= field->offset(record);
63
64
  /* Test if some key starts as fieldpos */
65
  for (i= 0, key_info= key ;
66
       i < (int) key_count ;
67
       i++, key_info++)
68
  {
69
    if (key_info->key_part[0].offset == fieldpos)
70
    {                                  		/* Found key. Calc keylength */
71
      *key_length= *keypart= 0;
72
      return i;                                 /* Use this key */
73
    }
74
  }
75
76
  /* Test if some key contains fieldpos */
77
  for (i= 0, key_info= key;
78
       i < (int) key_count ;
79
       i++, key_info++)
80
  {
482 by Brian Aker
Remove uint.
81
    uint32_t j;
1 by brian
clean slate
82
    KEY_PART_INFO *key_part;
83
    *key_length=0;
84
    for (j=0, key_part=key_info->key_part ;
85
	 j < key_info->key_parts ;
86
	 j++, key_part++)
87
    {
88
      if (key_part->offset == fieldpos)
89
      {
90
        *keypart= j;
91
        return i;                               /* Use this key */
92
      }
93
      *key_length+= key_part->store_length;
94
    }
95
  }
96
  return(-1);					/* No key is ok */
97
}
98
99
481 by Brian Aker
Remove all of uchar.
100
void key_copy(unsigned char *to_key, unsigned char *from_record, KEY *key_info,
287.3.8 by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get
101
              unsigned int key_length)
1 by brian
clean slate
102
{
482 by Brian Aker
Remove uint.
103
  uint32_t length;
1 by brian
clean slate
104
  KEY_PART_INFO *key_part;
105
106
  if (key_length == 0)
107
    key_length= key_info->key_length;
108
  for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
109
  {
110
    if (key_part->null_bit)
111
    {
112
      *to_key++= test(from_record[key_part->null_offset] &
113
		   key_part->null_bit);
114
      key_length--;
115
    }
116
    if (key_part->key_part_flag & HA_BLOB_PART ||
117
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
118
    {
119
      key_length-= HA_KEY_BLOB_LENGTH;
398.1.4 by Monty Taylor
Renamed max/min.
120
      length= cmin((uint16_t)key_length, key_part->length);
1 by brian
clean slate
121
      key_part->field->get_key_image(to_key, length, Field::itRAW);
122
      to_key+= HA_KEY_BLOB_LENGTH;
123
    }
124
    else
125
    {
398.1.4 by Monty Taylor
Renamed max/min.
126
      length= cmin((uint16_t)key_length, key_part->length);
1 by brian
clean slate
127
      Field *field= key_part->field;
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
128
      const CHARSET_INFO * const cs= field->charset();
482 by Brian Aker
Remove uint.
129
      uint32_t bytes= field->get_key_image(to_key, length, Field::itRAW);
1 by brian
clean slate
130
      if (bytes < length)
131
        cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
132
    }
133
    to_key+= length;
134
    key_length-= length;
135
  }
136
}
137
138
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
139
void key_copy(basic_string<unsigned char> &to_key,
140
              unsigned char *from_record, KEY *key_info,
141
              unsigned int key_length)
142
{
143
  uint32_t length;
144
  KEY_PART_INFO *key_part;
145
146
  if (key_length == 0)
147
    key_length= key_info->key_length;
148
  for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
149
  {
150
    if (key_part->null_bit)
151
    {
152
      to_key.push_back(test(from_record[key_part->null_offset] &
153
		       key_part->null_bit) ? '1' : '0');
154
      key_length--;
155
    }
156
    if (key_part->key_part_flag & HA_BLOB_PART ||
157
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
158
    {
159
      key_length-= HA_KEY_BLOB_LENGTH;
160
      length= cmin((uint16_t)key_length, key_part->length);
161
      key_part->field->get_key_image(to_key, length, Field::itRAW);
162
      to_key.append(HA_KEY_BLOB_LENGTH, '0');
163
    }
164
    else
165
    {
166
      length= cmin((uint16_t)key_length, key_part->length);
167
      Field *field= key_part->field;
168
      uint32_t bytes= field->get_key_image(to_key, length, Field::itRAW);
169
      if (bytes < length)
170
        to_key.append(length-bytes, ' ');
171
    }
172
    key_length-= length;
173
  }
174
}
175
176
1 by brian
clean slate
177
/**
178
  Zero the null components of key tuple.
179
*/
180
481 by Brian Aker
Remove all of uchar.
181
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
1 by brian
clean slate
182
{
183
  KEY_PART_INFO *key_part= key_info->key_part;
184
  KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
185
  for (; key_part != key_part_end; key_part++)
186
  {
187
    if (key_part->null_bit && *tuple)
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
188
      memset(tuple+1, 0, key_part->store_length-1);
1 by brian
clean slate
189
    tuple+= key_part->store_length;
190
  }
191
}
192
193
194
/*
195
  Restore a key from some buffer to record.
196
197
    This function converts a key into record format. It can be used in cases
198
    when we want to return a key as a result row.
199
200
  @param to_record   record buffer where the key will be restored to
201
  @param from_key    buffer that contains a key
202
  @param key_info    descriptor of the index
203
  @param key_length  specifies length of all keyparts that will be restored
204
*/
205
481 by Brian Aker
Remove all of uchar.
206
void key_restore(unsigned char *to_record, unsigned char *from_key, KEY *key_info,
287.3.8 by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get
207
                 uint16_t key_length)
1 by brian
clean slate
208
{
482 by Brian Aker
Remove uint.
209
  uint32_t length;
1 by brian
clean slate
210
  KEY_PART_INFO *key_part;
211
212
  if (key_length == 0)
213
  {
214
    key_length= key_info->key_length;
215
  }
216
  for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
217
  {
481 by Brian Aker
Remove all of uchar.
218
    unsigned char used_uneven_bits= 0;
1 by brian
clean slate
219
    if (key_part->null_bit)
220
    {
221
      if (*from_key++)
222
	to_record[key_part->null_offset]|= key_part->null_bit;
223
      else
224
	to_record[key_part->null_offset]&= ~key_part->null_bit;
225
      key_length--;
226
    }
227
    if (key_part->key_part_flag & HA_BLOB_PART)
228
    {
229
      /*
230
        This in fact never happens, as we have only partial BLOB
231
        keys yet anyway, so it's difficult to find any sence to
232
        restore the part of a record.
233
        Maybe this branch is to be removed, but now we
234
        have to ignore GCov compaining.
235
      */
482 by Brian Aker
Remove uint.
236
      uint32_t blob_length= uint2korr(from_key);
1 by brian
clean slate
237
      Field_blob *field= (Field_blob*) key_part->field;
238
      from_key+= HA_KEY_BLOB_LENGTH;
239
      key_length-= HA_KEY_BLOB_LENGTH;
240
      field->set_ptr_offset(to_record - field->table->record[0],
241
                            (ulong) blob_length, from_key);
242
      length= key_part->length;
243
    }
244
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
245
    {
246
      Field *field= key_part->field;
247
      my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
248
      field->move_field_offset(ptrdiff);
249
      key_length-= HA_KEY_BLOB_LENGTH;
398.1.4 by Monty Taylor
Renamed max/min.
250
      length= cmin(key_length, key_part->length);
1 by brian
clean slate
251
      field->set_key_image(from_key, length);
252
      from_key+= HA_KEY_BLOB_LENGTH;
253
      field->move_field_offset(-ptrdiff);
254
    }
255
    else
256
    {
398.1.4 by Monty Taylor
Renamed max/min.
257
      length= cmin(key_length, key_part->length);
1 by brian
clean slate
258
      /* skip the byte with 'uneven' bits, if used */
259
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
260
             , (size_t) length - used_uneven_bits);
261
    }
262
    from_key+= length;
263
    key_length-= length;
264
  }
265
}
266
267
268
/**
269
  Compare if a key has changed.
270
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
271
  @param table		Table
1 by brian
clean slate
272
  @param key		key to compare to row
273
  @param idx		Index used
274
  @param key_length	Length of key
275
276
  @note
277
    In theory we could just call field->cmp() for all field types,
278
    but as we are only interested if a key has changed (not if the key is
279
    larger or smaller than the previous value) we can do things a bit
280
    faster by using memcmp() instead.
281
282
  @retval
283
    0	If key is equal
284
  @retval
285
    1	Key has changed
286
*/
287
482 by Brian Aker
Remove uint.
288
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
1 by brian
clean slate
289
{
482 by Brian Aker
Remove uint.
290
  uint32_t store_length;
1 by brian
clean slate
291
  KEY_PART_INFO *key_part;
481 by Brian Aker
Remove all of uchar.
292
  const unsigned char *key_end= key + key_length;;
1 by brian
clean slate
293
294
  for (key_part=table->key_info[idx].key_part;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
295
       key < key_end ;
1 by brian
clean slate
296
       key_part++, key+= store_length)
297
  {
482 by Brian Aker
Remove uint.
298
    uint32_t length;
1 by brian
clean slate
299
    store_length= key_part->store_length;
300
301
    if (key_part->null_bit)
302
    {
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
303
      if (*key != test(table->record[0][key_part->null_offset] &
1 by brian
clean slate
304
		       key_part->null_bit))
305
	return 1;
306
      if (*key)
307
	continue;
308
      key++;
309
      store_length--;
310
    }
311
    if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
312
                                   HA_BIT_PART))
313
    {
314
      if (key_part->field->key_cmp(key, key_part->length))
315
	return 1;
316
      continue;
317
    }
895 by Brian Aker
Completion (?) of uint conversion.
318
    length= cmin((uint32_t) (key_end-key), store_length);
1 by brian
clean slate
319
    if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
320
                                FIELDFLAG_PACK)))
321
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
322
      const CHARSET_INFO * const cs= key_part->field->charset();
482 by Brian Aker
Remove uint.
323
      uint32_t char_length= key_part->length / cs->mbmaxlen;
481 by Brian Aker
Remove all of uchar.
324
      const unsigned char *pos= table->record[0] + key_part->offset;
1 by brian
clean slate
325
      if (length > char_length)
326
      {
327
        char_length= my_charpos(cs, pos, pos + length, char_length);
328
        set_if_smaller(char_length, length);
329
      }
330
      if (cs->coll->strnncollsp(cs,
481 by Brian Aker
Remove all of uchar.
331
                                (const unsigned char*) key, length,
332
                                (const unsigned char*) pos, char_length, 0))
1 by brian
clean slate
333
        return 1;
334
      continue;
335
    }
336
    if (memcmp(key,table->record[0]+key_part->offset,length))
337
      return 1;
338
  }
339
  return 0;
340
}
341
342
/*
343
  unpack key-fields from record to some buffer.
344
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
345
  This is used mainly to get a good error message.  We temporary
1 by brian
clean slate
346
  change the column bitmap so that all columns are readable.
347
348
  @param
349
     to		Store value here in an easy to read form
350
  @param
351
     table	Table to use
352
  @param
353
     idx	Key number
354
*/
355
482 by Brian Aker
Remove uint.
356
void key_unpack(String *to,Table *table,uint32_t idx)
1 by brian
clean slate
357
{
358
  KEY_PART_INFO *key_part,*key_part_end;
359
  Field *field;
360
  String tmp;
361
362
  to->length(0);
363
  for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
364
	 table->key_info[idx].key_parts ;
365
       key_part < key_part_end;
366
       key_part++)
367
  {
368
    if (to->length())
369
      to->append('-');
370
    if (key_part->null_bit)
371
    {
372
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
373
      {
374
	to->append(STRING_WITH_LEN("NULL"));
375
	continue;
376
      }
377
    }
378
    if ((field=key_part->field))
379
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
380
      const CHARSET_INFO * const cs= field->charset();
1 by brian
clean slate
381
      field->val_str(&tmp);
382
      if (cs->mbmaxlen > 1 &&
383
          table->field[key_part->fieldnr - 1]->field_length !=
384
          key_part->length)
385
      {
386
        /*
387
          Prefix key, multi-byte charset.
388
          For the columns of type CHAR(N), the above val_str()
389
          call will return exactly "key_part->length" bytes,
390
          which can break a multi-byte characters in the middle.
391
          Align, returning not more than "char_length" characters.
392
        */
482 by Brian Aker
Remove uint.
393
        uint32_t charpos, char_length= key_part->length / cs->mbmaxlen;
813.1.3 by Jay Pipes
Incorrectly passing str.ptr() instead of str.c_ptr() to my_charpos() in key.cc:key_unpack(). This resulted in duplicate key error messages containing random characters due to a bad offset, and would show up as random failure in the myisam.test case when running make test but not ./dtr myisam.
394
        if ((charpos= my_charpos(cs, tmp.c_ptr(),
395
                                 tmp.c_ptr() + tmp.length(),
1 by brian
clean slate
396
                                 char_length)) < key_part->length)
397
          tmp.length(charpos);
398
      }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
399
1 by brian
clean slate
400
      if (key_part->length < field->pack_length())
398.1.4 by Monty Taylor
Renamed max/min.
401
	tmp.length(cmin(tmp.length(),(uint32_t)key_part->length));
1 by brian
clean slate
402
      to->append(tmp);
403
    }
404
    else
405
      to->append(STRING_WITH_LEN("???"));
406
  }
327.2.3 by Brian Aker
Refactoring of class Table
407
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
408
  return;
1 by brian
clean slate
409
}
410
411
412
/*
413
  Check if key uses field that is marked in passed field bitmap.
414
415
  SYNOPSIS
416
    is_key_used()
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
417
      table   Table object with which keys and fields are associated.
1 by brian
clean slate
418
      idx     Key to be checked.
419
      fields  Bitmap of fields to be checked.
420
421
  NOTE
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
422
    This function uses Table::tmp_set bitmap so the caller should care
1 by brian
clean slate
423
    about saving/restoring its state if it also uses this bitmap.
424
425
  RETURN VALUE
426
    TRUE   Key uses field from bitmap
427
    FALSE  Otherwise
428
*/
429
482 by Brian Aker
Remove uint.
430
bool is_key_used(Table *table, uint32_t idx, const MY_BITMAP *fields)
1 by brian
clean slate
431
{
432
  bitmap_clear_all(&table->tmp_set);
433
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
434
  if (bitmap_is_overlapping(&table->tmp_set, fields))
435
    return 1;
436
437
  /*
438
    If table handler has primary key as part of the index, check that primary
439
    key is not updated
440
  */
441
  if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
442
      (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX))
443
    return is_key_used(table, table->s->primary_key, fields);
444
  return 0;
445
}
446
447
448
/**
449
  Compare key in row to a given key.
450
451
  @param key_part		Key part handler
452
  @param key			Key to compare to value in table->record[0]
453
  @param key_length		length of 'key'
454
455
  @return
456
    The return value is SIGN(key_in_row - range_key):
457
    -   0		Key is equal to range or 'range' == 0 (no range)
458
    -  -1		Key is less than range
459
    -   1		Key is larger than range
460
*/
461
482 by Brian Aker
Remove uint.
462
int key_cmp(KEY_PART_INFO *key_part, const unsigned char *key, uint32_t key_length)
1 by brian
clean slate
463
{
482 by Brian Aker
Remove uint.
464
  uint32_t store_length;
1 by brian
clean slate
465
481 by Brian Aker
Remove all of uchar.
466
  for (const unsigned char *end=key + key_length;
1 by brian
clean slate
467
       key < end;
468
       key+= store_length, key_part++)
469
  {
470
    int cmp;
471
    store_length= key_part->store_length;
472
    if (key_part->null_bit)
473
    {
474
      /* This key part allows null values; NULL is lower than everything */
475
      register bool field_is_null= key_part->field->is_null();
476
      if (*key)                                 // If range key is null
477
      {
478
	/* the range is expecting a null value */
479
	if (!field_is_null)
480
	  return 1;                             // Found key is > range
481
        /* null -- exact match, go to next key part */
482
	continue;
483
      }
484
      else if (field_is_null)
485
	return -1;                              // NULL is less than any value
486
      key++;					// Skip null byte
487
      store_length--;
488
    }
489
    if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
490
      return -1;
491
    if (cmp > 0)
492
      return 1;
493
  }
494
  return 0;                                     // Keys are equal
495
}
496
497
498
/*
499
  Compare two records in index order
500
  SYNOPSIS
501
    key_rec_cmp()
502
    key                         Index information
503
    rec0                        Pointer to table->record[0]
504
    first_rec                   Pointer to record compare with
505
    second_rec                  Pointer to record compare against first_rec
506
507
  DESCRIPTION
508
    This method is set-up such that it can be called directly from the
509
    priority queue and it is attempted to be optimised as much as possible
510
    since this will be called O(N * log N) times while performing a merge
511
    sort in various places in the code.
512
513
    We retrieve the pointer to table->record[0] using the fact that key_parts
514
    have an offset making it possible to calculate the start of the record.
515
    We need to get the diff to the compared record since none of the records
516
    being compared are stored in table->record[0].
517
518
    We first check for NULL values, if there are no NULL values we use
519
    a compare method that gets two field pointers and a max length
520
    and return the result of the comparison.
521
*/
522
481 by Brian Aker
Remove all of uchar.
523
int key_rec_cmp(void *key, unsigned char *first_rec, unsigned char *second_rec)
1 by brian
clean slate
524
{
525
  KEY *key_info= (KEY*)key;
482 by Brian Aker
Remove uint.
526
  uint32_t key_parts= key_info->key_parts, i= 0;
1 by brian
clean slate
527
  KEY_PART_INFO *key_part= key_info->key_part;
481 by Brian Aker
Remove all of uchar.
528
  unsigned char *rec0= key_part->field->ptr - key_part->offset;
1 by brian
clean slate
529
  my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
530
  int result= 0;
531
532
  do
533
  {
534
    Field *field= key_part->field;
535
536
    if (key_part->null_bit)
537
    {
538
      /* The key_part can contain NULL values */
539
      bool first_is_null= field->is_null_in_record_with_offset(first_diff);
540
      bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
541
      /*
542
        NULL is smaller then everything so if first is NULL and the other
543
        not then we know that we should return -1 and for the opposite
544
        we should return +1. If both are NULL then we call it equality
545
        although it is a strange form of equality, we have equally little
546
        information of the real value.
547
      */
548
      if (!first_is_null)
549
      {
550
        if (!sec_is_null)
551
          ; /* Fall through, no NULL fields */
552
        else
553
        {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
554
          return(1);
1 by brian
clean slate
555
        }
556
      }
557
      else if (!sec_is_null)
558
      {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
559
        return(-1);
1 by brian
clean slate
560
      }
561
      else
562
        goto next_loop; /* Both were NULL */
563
    }
564
    /*
565
      No null values in the fields
566
      We use the virtual method cmp_max with a max length parameter.
567
      For most field types this translates into a cmp without
568
      max length. The exceptions are the BLOB and VARCHAR field types
569
      that take the max length into account.
570
    */
571
    result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
572
                           key_part->length);
573
next_loop:
574
    key_part++;
575
  } while (!result && ++i < key_parts);
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
576
  return(result);
1 by brian
clean slate
577
}
934.2.21 by Jay Pipes
Move Key stuff into key.cc and out of session.cc
578
579
Key::Key(const Key &rhs, MEM_ROOT *mem_root)
580
  :type(rhs.type),
581
  key_create_info(rhs.key_create_info),
582
  columns(rhs.columns, mem_root),
583
  name(rhs.name),
584
  generated(rhs.generated)
585
{
586
  list_copy_and_replace_each_value(columns, mem_root);
587
}