~drizzle-trunk/drizzle/development

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