~drizzle-trunk/drizzle/development

319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
1
#ifndef INCLUDES_DRIZZLE_SQL_LIST_H
2
#define INCLUDES_DRIZZLE_SQL_LIST_H
1 by brian
clean slate
3
/* Copyright (C) 2000-2003 MySQL AB
4
5
   This program is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; version 2 of the License.
8
9
   This program is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with this program; if not, write to the Free Software
16
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
17
18
19
#ifdef USE_PRAGMA_INTERFACE
20
#pragma interface			/* gcc class implementation */
21
#endif
322.2.2 by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter.
22
23
#include <utility>
24
243.1.1 by Jay Pipes
* Pulled Object_creation_ctx and Default_creation_ctx out of mysql_priv.h
25
/** Struct to handle simple linked lists. */
26
typedef struct st_sql_list {
27
  uint elements;
28
  uchar *first;
29
  uchar **next;
30
31
  st_sql_list() {}                              /* Remove gcc warning */
32
  inline void empty()
33
  {
34
    elements=0;
35
    first=0;
36
    next= &first;
37
  }
38
  inline void link_in_list(uchar *element,uchar **next_ptr)
39
  {
40
    elements++;
41
    (*next)=element;
42
    next= next_ptr;
43
    *next=0;
44
  }
45
  inline void save_and_clear(struct st_sql_list *save)
46
  {
47
    *save= *this;
48
    empty();
49
  }
50
  inline void push_front(struct st_sql_list *save)
51
  {
52
    *save->next= first;				/* link current list last */
53
    first= save->first;
54
    elements+= save->elements;
55
  }
56
  inline void push_back(struct st_sql_list *save)
57
  {
58
    if (save->first)
59
    {
60
      *next= save->first;
61
      next= save->next;
62
      elements+= save->elements;
63
    }
64
  }
65
} SQL_LIST;
1 by brian
clean slate
66
67
/* mysql standard class memory allocator */
68
class Sql_alloc
69
{
70
public:
71
  static void *operator new(size_t size) throw ()
72
  {
73
    return sql_alloc(size);
74
  }
75
  static void *operator new[](size_t size)
76
  {
77
    return sql_alloc(size);
78
  }
79
  static void *operator new[](size_t size, MEM_ROOT *mem_root) throw ()
80
  { return alloc_root(mem_root, size); }
81
  static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
82
  { return alloc_root(mem_root, size); }
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
83
  static void operator delete(void *ptr __attribute__((unused)),
84
                              size_t size __attribute__((unused)))
53.2.32 by Monty Taylor
First large swath at getting handler stuff clean.
85
  { TRASH(ptr, size); }
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
86
  static void operator delete(void *ptr __attribute__((unused)),
87
                              MEM_ROOT *mem_root __attribute__((unused)))
88
  { /* never called */ }
89
  static void operator delete[](void *ptr __attribute__((unused)),
90
                                MEM_ROOT *mem_root __attribute__((unused)))
91
  { /* never called */ }
92
  static void operator delete[](void *ptr __attribute__((unused)),
93
                                size_t size __attribute__((unused)))
53.2.32 by Monty Taylor
First large swath at getting handler stuff clean.
94
  { TRASH(ptr, size); }
1 by brian
clean slate
95
#ifdef HAVE_purify
96
  bool dummy;
97
  inline Sql_alloc() :dummy(0) {}
98
  inline ~Sql_alloc() {}
99
#else
100
  inline Sql_alloc() {}
101
  inline ~Sql_alloc() {}
102
#endif
103
104
};
105
106
107
/*
108
  Basic single linked list
109
  Used for item and item_buffs.
110
  All list ends with a pointer to the 'end_of_list' element, which
111
  data pointer is a null pointer and the next pointer points to itself.
112
  This makes it very fast to traverse lists as we don't have to
113
  test for a specialend condition for list that can't contain a null
114
  pointer.
115
*/
116
117
118
/**
119
  list_node - a node of a single-linked list.
120
  @note We never call a destructor for instances of this class.
121
*/
122
123
struct list_node :public Sql_alloc
124
{
125
  list_node *next;
126
  void *info;
127
  list_node(void *info_par,list_node *next_par)
128
    :next(next_par),info(info_par)
129
  {}
130
  list_node()					/* For end_of_list */
131
  {
132
    info= 0;
133
    next= this;
134
  }
135
};
136
137
138
extern list_node end_of_list;
139
140
class base_list :public Sql_alloc
141
{
142
protected:
143
  list_node *first,**last;
144
145
public:
146
  uint elements;
147
148
  inline void empty() { elements=0; first= &end_of_list; last=&first;}
149
  inline base_list() { empty(); }
150
  /**
151
    This is a shallow copy constructor that implicitly passes the ownership
152
    from the source list to the new instance. The old instance is not
153
    updated, so both objects end up sharing the same nodes. If one of
154
    the instances then adds or removes a node, the other becomes out of
155
    sync ('last' pointer), while still operational. Some old code uses and
156
    relies on this behaviour. This logic is quite tricky: please do not use
157
    it in any new code.
158
  */
159
  inline base_list(const base_list &tmp) :Sql_alloc()
160
  {
161
    elements= tmp.elements;
162
    first= tmp.first;
163
    last= elements ? tmp.last : &first;
164
  }
165
  /**
166
    Construct a deep copy of the argument in memory root mem_root.
167
    The elements themselves are copied by pointer. If you also
168
    need to copy elements by value, you should employ
169
    list_copy_and_replace_each_value after creating a copy.
170
  */
171
  base_list(const base_list &rhs, MEM_ROOT *mem_root);
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
172
  inline base_list(bool error __attribute__((unused))) { }
1 by brian
clean slate
173
  inline bool push_back(void *info)
174
  {
175
    if (((*last)=new list_node(info, &end_of_list)))
176
    {
177
      last= &(*last)->next;
178
      elements++;
179
      return 0;
180
    }
181
    return 1;
182
  }
183
  inline bool push_back(void *info, MEM_ROOT *mem_root)
184
  {
185
    if (((*last)=new (mem_root) list_node(info, &end_of_list)))
186
    {
187
      last= &(*last)->next;
188
      elements++;
189
      return 0;
190
    }
191
    return 1;
192
  }
193
  inline bool push_front(void *info)
194
  {
195
    list_node *node=new list_node(info,first);
196
    if (node)
197
    {
198
      if (last == &first)
199
	last= &node->next;
200
      first=node;
201
      elements++;
202
      return 0;
203
    }
204
    return 1;
205
  }
206
  void remove(list_node **prev)
207
  {
208
    list_node *node=(*prev)->next;
209
    if (!--elements)
210
      last= &first;
211
    else if (last == &(*prev)->next)
212
      last= prev;
213
    delete *prev;
214
    *prev=node;
215
  }
216
  inline void concat(base_list *list)
217
  {
218
    if (!list->is_empty())
219
    {
220
      *last= list->first;
221
      last= list->last;
222
      elements+= list->elements;
223
    }
224
  }
225
  inline void *pop(void)
226
  {
227
    if (first == &end_of_list) return 0;
228
    list_node *tmp=first;
229
    first=first->next;
230
    if (!--elements)
231
      last= &first;
232
    return tmp->info;
233
  }
234
  inline void disjoin(base_list *list)
235
  {
236
    list_node **prev= &first;
237
    list_node *node= first;
238
    list_node *list_first= list->first;
239
    elements=0;
240
    while (node && node != list_first)
241
    {
242
      prev= &node->next;
243
      node= node->next;
244
      elements++;
245
    }
246
    *prev= *last;
247
    last= prev;
248
  }
249
  inline void prepand(base_list *list)
250
  {
251
    if (!list->is_empty())
252
    {
253
      *list->last= first;
254
      first= list->first;
255
      elements+= list->elements;
256
    }
257
  }
258
  /**
259
    Swap two lists.
260
  */
261
  inline void swap(base_list &rhs)
262
  {
322.2.2 by Mats Kindahl
Hiding THD::proc_info field and providing a setter and getter.
263
    std::swap(first, rhs.first);
264
    std::swap(last, rhs.last);
265
    std::swap(elements, rhs.elements);
1 by brian
clean slate
266
  }
267
  inline list_node* last_node() { return *last; }
268
  inline list_node* first_node() { return first;}
269
  inline void *head() { return first->info; }
270
  inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
271
  inline bool is_empty() { return first == &end_of_list ; }
272
  inline list_node *last_ref() { return &end_of_list; }
273
  friend class base_list_iterator;
274
  friend class error_list;
275
  friend class error_list_iterator;
276
277
#ifdef LIST_EXTRA_DEBUG
278
  /*
279
    Check list invariants and print results into trace. Invariants are:
280
      - (*last) points to end_of_list
281
      - There are no NULLs in the list.
282
      - base_list::elements is the number of elements in the list.
283
284
    SYNOPSIS
285
      check_list()
286
        name  Name to print to trace file
287
288
    RETURN 
289
      1  The list is Ok.
290
      0  List invariants are not met.
291
  */
292
293
  bool check_list(const char *name)
294
  {
295
    base_list *list= this;
296
    list_node *node= first;
297
    uint cnt= 0;
298
299
    while (node->next != &end_of_list)
300
    {
301
      if (!node->info)
302
      {
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
303
        return false;
1 by brian
clean slate
304
      }
305
      node= node->next;
306
      cnt++;
307
    }
308
    if (last != &(node->next))
309
    {
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
310
      return false;
1 by brian
clean slate
311
    }
312
    if (cnt+1 != elements)
313
    {
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
314
      return false;
1 by brian
clean slate
315
    }
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
316
    return true;
1 by brian
clean slate
317
  }
318
#endif // LIST_EXTRA_DEBUG
319
320
protected:
321
  void after(void *info,list_node *node)
322
  {
323
    list_node *new_node=new list_node(info,node->next);
324
    node->next=new_node;
325
    elements++;
326
    if (last == &(node->next))
327
      last= &new_node->next;
328
  }
329
};
330
331
332
class base_list_iterator
333
{
334
protected:
335
  base_list *list;
336
  list_node **el,**prev,*current;
337
  void sublist(base_list &ls, uint elm)
338
  {
339
    ls.first= *el;
340
    ls.last= list->last;
341
    ls.elements= elm;
342
  }
343
public:
344
  base_list_iterator() 
345
    :list(0), el(0), prev(0), current(0)
346
  {}
347
348
  base_list_iterator(base_list &list_par) 
349
  { init(list_par); }
350
351
  inline void init(base_list &list_par)
352
  {
353
    list= &list_par;
354
    el= &list_par.first;
355
    prev= 0;
356
    current= 0;
357
  }
358
359
  inline void *next(void)
360
  {
361
    prev=el;
362
    current= *el;
363
    el= &current->next;
364
    return current->info;
365
  }
366
  inline void *next_fast(void)
367
  {
368
    list_node *tmp;
369
    tmp= *el;
370
    el= &tmp->next;
371
    return tmp->info;
372
  }
373
  inline void rewind(void)
374
  {
375
    el= &list->first;
376
  }
377
  inline void *replace(void *element)
378
  {						// Return old element
379
    void *tmp=current->info;
51.1.53 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
380
    assert(current->info != 0);
1 by brian
clean slate
381
    current->info=element;
382
    return tmp;
383
  }
384
  void *replace(base_list &new_list)
385
  {
386
    void *ret_value=current->info;
387
    if (!new_list.is_empty())
388
    {
389
      *new_list.last=current->next;
390
      current->info=new_list.first->info;
391
      current->next=new_list.first->next;
392
      if ((list->last == &current->next) && (new_list.elements > 1))
393
	list->last= new_list.last;
394
      list->elements+=new_list.elements-1;
395
    }
396
    return ret_value;				// return old element
397
  }
398
  inline void remove(void)			// Remove current
399
  {
400
    list->remove(prev);
401
    el=prev;
402
    current=0;					// Safeguard
403
  }
404
  void after(void *element)			// Insert element after current
405
  {
406
    list->after(element,current);
407
    current=current->next;
408
    el= &current->next;
409
  }
410
  inline void **ref(void)			// Get reference pointer
411
  {
412
    return &current->info;
413
  }
414
  inline bool is_last(void)
415
  {
416
    return el == &list->last_ref()->next;
417
  }
418
  friend class error_list_iterator;
419
};
420
421
template <class T> class List :public base_list
422
{
423
public:
424
  inline List() :base_list() {}
425
  inline List(const List<T> &tmp) :base_list(tmp) {}
426
  inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
427
    base_list(tmp, mem_root) {}
428
  inline bool push_back(T *a) { return base_list::push_back(a); }
429
  inline bool push_back(T *a, MEM_ROOT *mem_root)
430
  { return base_list::push_back(a, mem_root); }
431
  inline bool push_front(T *a) { return base_list::push_front(a); }
432
  inline T* head() {return (T*) base_list::head(); }
433
  inline T** head_ref() {return (T**) base_list::head_ref(); }
434
  inline T* pop()  {return (T*) base_list::pop(); }
435
  inline void concat(List<T> *list) { base_list::concat(list); }
436
  inline void disjoin(List<T> *list) { base_list::disjoin(list); }
437
  inline void prepand(List<T> *list) { base_list::prepand(list); }
438
  void delete_elements(void)
439
  {
440
    list_node *element,*next;
441
    for (element=first; element != &end_of_list; element=next)
442
    {
443
      next=element->next;
444
      delete (T*) element->info;
445
    }
446
    empty();
447
  }
448
};
449
450
451
template <class T> class List_iterator :public base_list_iterator
452
{
453
public:
454
  List_iterator(List<T> &a) : base_list_iterator(a) {}
455
  List_iterator() : base_list_iterator() {}
456
  inline void init(List<T> &a) { base_list_iterator::init(a); }
457
  inline T* operator++(int) { return (T*) base_list_iterator::next(); }
458
  inline T *replace(T *a)   { return (T*) base_list_iterator::replace(a); }
459
  inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
460
  inline void rewind(void)  { base_list_iterator::rewind(); }
461
  inline void remove()      { base_list_iterator::remove(); }
462
  inline void after(T *a)   { base_list_iterator::after(a); }
463
  inline T** ref(void)	    { return (T**) base_list_iterator::ref(); }
464
};
465
466
467
template <class T> class List_iterator_fast :public base_list_iterator
468
{
469
protected:
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
470
  inline T *replace(T *a __attribute__((unused)))   { return (T*) 0; }
471
  inline T *replace(List<T> &a __attribute__((unused))) { return (T*) 0; }
1 by brian
clean slate
472
  inline void remove(void)  { }
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
473
  inline void after(T *a __attribute__((unused)))   { }
1 by brian
clean slate
474
  inline T** ref(void)	    { return (T**) 0; }
475
476
public:
477
  inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
478
  inline List_iterator_fast() : base_list_iterator() {}
479
  inline void init(List<T> &a) { base_list_iterator::init(a); }
480
  inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
481
  inline void rewind(void)  { base_list_iterator::rewind(); }
482
  void sublist(List<T> &list_arg, uint el_arg)
483
  {
484
    base_list_iterator::sublist(list_arg, el_arg);
485
  }
486
};
487
488
489
/*
490
  A simple intrusive list which automaticly removes element from list
491
  on delete (for THD element)
492
*/
493
494
struct ilink
495
{
496
  struct ilink **prev,*next;
497
  static void *operator new(size_t size)
498
  {
499
    return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATALERROR));
500
  }
53.2.32 by Monty Taylor
First large swath at getting handler stuff clean.
501
  static void operator delete(void* ptr_arg,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
502
                              size_t size __attribute__((unused)))
1 by brian
clean slate
503
  {
504
     my_free((uchar*)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
505
  }
506
507
  inline ilink()
508
  {
509
    prev=0; next=0;
510
  }
511
  inline void unlink()
512
  {
513
    /* Extra tests because element doesn't have to be linked */
514
    if (prev) *prev= next;
515
    if (next) next->prev=prev;
516
    prev=0 ; next=0;
517
  }
518
  virtual ~ilink() { unlink(); }		/*lint -e1740 */
519
};
520
521
522
/* Needed to be able to have an I_List of char* strings in mysqld.cc. */
523
524
class i_string: public ilink
525
{
526
public:
527
  const char* ptr;
528
  i_string():ptr(0) { }
529
  i_string(const char* s) : ptr(s) {}
530
};
531
532
/* needed for linked list of two strings for replicate-rewrite-db */
533
class i_string_pair: public ilink
534
{
535
public:
536
  const char* key;
537
  const char* val;
538
  i_string_pair():key(0),val(0) { }
539
  i_string_pair(const char* key_arg, const char* val_arg) : 
540
    key(key_arg),val(val_arg) {}
541
};
542
543
544
template <class T> class I_List_iterator;
545
546
/*
547
  WARNING: copy constructor of this class does not create a usable
548
  copy, as its members may point at each other.
549
*/
550
551
class base_ilist
552
{
553
public:
554
  struct ilink *first,last;
555
  inline void empty() { first= &last; last.prev= &first; }
556
  base_ilist() { empty(); }
557
  inline bool is_empty() {  return first == &last; }
558
  inline void append(ilink *a)
559
  {
560
    first->prev= &a->next;
561
    a->next=first; a->prev= &first; first=a;
562
  }
563
  inline void push_back(ilink *a)
564
  {
565
    *last.prev= a;
566
    a->next= &last;
567
    a->prev= last.prev;
568
    last.prev= &a->next;
569
  }
570
  inline struct ilink *get()
571
  {
572
    struct ilink *first_link=first;
573
    if (first_link == &last)
574
      return 0;
575
    first_link->unlink();			// Unlink from list
576
    return first_link;
577
  }
578
  inline struct ilink *head()
579
  {
580
    return (first != &last) ? first : 0;
581
  }
582
  friend class base_list_iterator;
583
};
584
585
586
class base_ilist_iterator
587
{
588
  base_ilist *list;
589
  struct ilink **el,*current;
590
public:
591
  base_ilist_iterator(base_ilist &list_par) :list(&list_par),
592
    el(&list_par.first),current(0) {}
593
  void *next(void)
594
  {
595
    /* This is coded to allow push_back() while iterating */
596
    current= *el;
597
    if (current == &list->last) return 0;
598
    el= &current->next;
599
    return current;
600
  }
601
};
602
603
604
template <class T>
605
class I_List :private base_ilist
606
{
607
public:
608
  I_List() :base_ilist()	{}
609
  inline void empty()		{ base_ilist::empty(); }
610
  inline bool is_empty()        { return base_ilist::is_empty(); } 
611
  inline void append(T* a)	{ base_ilist::append(a); }
612
  inline void push_back(T* a)	{ base_ilist::push_back(a); }
613
  inline T* get()		{ return (T*) base_ilist::get(); }
614
  inline T* head()		{ return (T*) base_ilist::head(); }
615
#ifndef _lint
616
  friend class I_List_iterator<T>;
617
#endif
618
};
619
620
621
template <class T> class I_List_iterator :public base_ilist_iterator
622
{
623
public:
624
  I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {}
625
  inline T* operator++(int) { return (T*) base_ilist_iterator::next(); }
626
};
627
628
/**
629
  Make a deep copy of each list element.
630
631
  @note A template function and not a template method of class List
632
  is employed because of explicit template instantiation:
633
  in server code there are explicit instantiations of List<T> and
634
  an explicit instantiation of a template requires that any method
635
  of the instantiated class used in the template can be resolved.
636
  Evidently not all template arguments have clone() method with
637
  the right signature.
638
639
  @return You must query the error state in THD for out-of-memory
640
  situation after calling this function.
641
*/
642
643
template <typename T>
644
inline
645
void
646
list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root)
647
{
648
  /* Make a deep copy of each element */
649
  List_iterator<T> it(list);
650
  T *el;
651
  while ((el= it++))
652
    it.replace(el->clone(mem_root));
653
}
654
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
655
#endif // INCLUDES_DRIZZLE_SQL_LIST_H