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