~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/table_share.h

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2009 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; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
 
 */
20
 
 
21
 
/*
22
 
  This class is shared between different table objects. There is one
23
 
  instance of table share per one table in the database.
24
 
*/
25
 
 
26
 
#ifndef DRIZZLED_TABLE_SHARE_H
27
 
#define DRIZZLED_TABLE_SHARE_H
28
 
 
29
 
#include <string>
30
 
 
31
 
#include "drizzled/typelib.h"
32
 
#include "drizzled/my_hash.h"
33
 
#include "drizzled/memory/root.h"
34
 
#include "drizzled/message/table.pb.h"
35
 
 
36
 
namespace drizzled
37
 
{
38
 
 
39
 
typedef drizzled::hash_map<std::string, TableShare *> TableDefinitionCache;
40
 
 
41
 
const static std::string STANDARD_STRING("STANDARD");
42
 
const static std::string TEMPORARY_STRING("TEMPORARY");
43
 
const static std::string INTERNAL_STRING("INTERNAL");
44
 
const static std::string FUNCTION_STRING("FUNCTION");
45
 
 
46
 
class TableShare
47
 
{
48
 
public:
49
 
  TableShare() :
50
 
    table_category(TABLE_UNKNOWN_CATEGORY),
51
 
    open_count(0),
52
 
    field(NULL),
53
 
    found_next_number_field(NULL),
54
 
    timestamp_field(NULL),
55
 
    key_info(NULL),
56
 
    blob_field(NULL),
57
 
    intervals(NULL),
58
 
    default_values(NULL),
59
 
    block_size(0),
60
 
    version(0),
61
 
    timestamp_offset(0),
62
 
    reclength(0),
63
 
    stored_rec_length(0),
64
 
    row_type(ROW_TYPE_DEFAULT),
65
 
    max_rows(0),
66
 
    table_proto(NULL),
67
 
    storage_engine(NULL),
68
 
    tmp_table(message::Table::STANDARD),
69
 
    ref_count(0),
70
 
    null_bytes(0),
71
 
    last_null_bit_pos(0),
72
 
    fields(0),
73
 
    rec_buff_length(0),
74
 
    keys(0),
75
 
    key_parts(0),
76
 
    max_key_length(0),
77
 
    max_unique_length(0),
78
 
    total_key_length(0),
79
 
    uniques(0),
80
 
    null_fields(0),
81
 
    blob_fields(0),
82
 
    timestamp_field_offset(0),
83
 
    varchar_fields(0),
84
 
    db_create_options(0),
85
 
    db_options_in_use(0),
86
 
    db_record_offset(0),
87
 
    rowid_field_offset(0),
88
 
    primary_key(0),
89
 
    next_number_index(0),
90
 
    next_number_key_offset(0),
91
 
    next_number_keypart(0),
92
 
    error(0),
93
 
    open_errno(0),
94
 
    errarg(0),
95
 
    column_bitmap_size(0),
96
 
    blob_ptr_size(0),
97
 
    db_low_byte_first(false),
98
 
    name_lock(false),
99
 
    replace_with_name_lock(false),
100
 
    waiting_on_cond(false),
101
 
    keys_in_use(0),
102
 
    keys_for_keyread(0)
103
 
  {
104
 
    init();
105
 
  }
106
 
 
107
 
  TableShare(const char *key,
108
 
             uint32_t key_length,
109
 
             const char *new_table_name,
110
 
             const char *new_path) :
111
 
    table_category(TABLE_UNKNOWN_CATEGORY),
112
 
    open_count(0),
113
 
    field(NULL),
114
 
    found_next_number_field(NULL),
115
 
    timestamp_field(NULL),
116
 
    key_info(NULL),
117
 
    blob_field(NULL),
118
 
    intervals(NULL),
119
 
    default_values(NULL),
120
 
    block_size(0),
121
 
    version(0),
122
 
    timestamp_offset(0),
123
 
    reclength(0),
124
 
    stored_rec_length(0),
125
 
    row_type(ROW_TYPE_DEFAULT),
126
 
    max_rows(0),
127
 
    table_proto(NULL),
128
 
    storage_engine(NULL),
129
 
    tmp_table(message::Table::STANDARD),
130
 
    ref_count(0),
131
 
    null_bytes(0),
132
 
    last_null_bit_pos(0),
133
 
    fields(0),
134
 
    rec_buff_length(0),
135
 
    keys(0),
136
 
    key_parts(0),
137
 
    max_key_length(0),
138
 
    max_unique_length(0),
139
 
    total_key_length(0),
140
 
    uniques(0),
141
 
    null_fields(0),
142
 
    blob_fields(0),
143
 
    timestamp_field_offset(0),
144
 
    varchar_fields(0),
145
 
    db_create_options(0),
146
 
    db_options_in_use(0),
147
 
    db_record_offset(0),
148
 
    rowid_field_offset(0),
149
 
    primary_key(0),
150
 
    next_number_index(0),
151
 
    next_number_key_offset(0),
152
 
    next_number_keypart(0),
153
 
    error(0),
154
 
    open_errno(0),
155
 
    errarg(0),
156
 
    column_bitmap_size(0),
157
 
    blob_ptr_size(0),
158
 
    db_low_byte_first(false),
159
 
    name_lock(false),
160
 
    replace_with_name_lock(false),
161
 
    waiting_on_cond(false),
162
 
    keys_in_use(0),
163
 
    keys_for_keyread(0)
164
 
  {
165
 
    init(key, key_length, new_table_name, new_path);
166
 
  }
167
 
 
168
 
  /** Category of this table. */
169
 
  enum_table_category table_category;
170
 
 
171
 
  uint32_t open_count;                  /* Number of tables in open list */
172
 
 
173
 
  /* The following is copied to each Table on OPEN */
174
 
  Field **field;
175
 
  Field **found_next_number_field;
176
 
  Field *timestamp_field;               /* Used only during open */
177
 
  KEY  *key_info;                       /* data of keys in database */
178
 
  uint  *blob_field;                    /* Index to blobs in Field arrray*/
179
 
 
180
 
  /* hash of field names (contains pointers to elements of field array) */
181
 
  HASH  name_hash;                      /* hash of field names */
182
 
  memory::Root mem_root;
183
 
  TYPELIB keynames;                     /* Pointers to keynames */
184
 
  TYPELIB fieldnames;                   /* Pointer to fieldnames */
185
 
  TYPELIB *intervals;                   /* pointer to interval info */
186
 
  pthread_mutex_t mutex;                /* For locking the share  */
187
 
  pthread_cond_t cond;                  /* To signal that share is ready */
188
 
 
189
 
  unsigned char *default_values;                /* row with default values */
190
 
  const CHARSET_INFO *table_charset; /* Default charset of string fields */
191
 
 
192
 
  MyBitmap all_set;
193
 
  /*
194
 
    Key which is used for looking-up table in table cache and in the list
195
 
    of thread's temporary tables. Has the form of:
196
 
    "database_name\0table_name\0" + optional part for temporary tables.
197
 
 
198
 
    Note that all three 'table_cache_key', 'db' and 'table_name' members
199
 
    must be set (and be non-zero) for tables in table cache. They also
200
 
    should correspond to each other.
201
 
    To ensure this one can use set_table_cache() methods.
202
 
  */
203
 
  LEX_STRING table_cache_key;
204
 
private:
205
 
  LEX_STRING db;                        /* Pointer to db */
206
 
public:
207
 
  LEX_STRING table_name;                /* Table name (for open) */
208
 
  LEX_STRING path;      /* Path to table (from datadir) */
209
 
  LEX_STRING normalized_path;           /* unpack_filename(path) */
210
 
 
211
 
  const char *getTableName() const
212
 
  {
213
 
    return table_name.str;
214
 
  }
215
 
 
216
 
  const char *getPath() const
217
 
  {
218
 
    return path.str;
219
 
  }
220
 
 
221
 
  const std::string &getTableName(std::string &name_arg) const
222
 
  {
223
 
    name_arg.clear();
224
 
    name_arg.append(table_name.str, table_name.length);
225
 
 
226
 
    return name_arg;
227
 
  }
228
 
 
229
 
  const char *getSchemaName() const
230
 
  {
231
 
    return db.str;
232
 
  }
233
 
 
234
 
  const std::string &getSchemaName(std::string &schema_name_arg) const
235
 
  {
236
 
    schema_name_arg.clear();
237
 
    schema_name_arg.append(db.str, db.length);
238
 
 
239
 
    return schema_name_arg;
240
 
  }
241
 
 
242
 
  uint32_t   block_size;                   /* create information */
243
 
 
244
 
  uint64_t   version;
245
 
  uint64_t getVersion()
246
 
  {
247
 
    return version;
248
 
  }
249
 
 
250
 
  uint32_t   timestamp_offset;          /* Set to offset+1 of record */
251
 
  uint32_t   reclength;                 /* Recordlength */
252
 
  uint32_t   stored_rec_length;         /* Stored record length*/
253
 
  enum row_type row_type;               /* How rows are stored */
254
 
 
255
 
  uint32_t getRecordLength()
256
 
  {
257
 
    return reclength;
258
 
  }
259
 
 
260
 
private:
261
 
  /* Max rows is a hint to HEAP during a create tmp table */
262
 
  uint64_t max_rows;
263
 
 
264
 
  message::Table *table_proto;
265
 
public:
266
 
 
267
 
  const std::string &getTableTypeAsString() const
268
 
  {
269
 
    switch (table_proto->type())
270
 
    {
271
 
    default:
272
 
    case message::Table::STANDARD:
273
 
      return STANDARD_STRING;
274
 
    case message::Table::TEMPORARY:
275
 
      return TEMPORARY_STRING;
276
 
    case message::Table::INTERNAL:
277
 
      return INTERNAL_STRING;
278
 
    case message::Table::FUNCTION:
279
 
      return FUNCTION_STRING;
280
 
    }
281
 
  }
282
 
 
283
 
  /* This is only used in one location currently */
284
 
  inline message::Table *getTableProto() const
285
 
  {
286
 
    return table_proto;
287
 
  }
288
 
 
289
 
  inline void setTableProto(message::Table *arg)
290
 
  {
291
 
    assert(table_proto == NULL);
292
 
    table_proto= arg;
293
 
  }
294
 
 
295
 
  inline bool hasComment()
296
 
  {
297
 
    return (table_proto) ?  table_proto->options().has_comment() : false; 
298
 
  }
299
 
 
300
 
  inline const char *getComment()
301
 
  {
302
 
    return (table_proto && table_proto->has_options()) ?  table_proto->options().comment().c_str() : NULL; 
303
 
  }
304
 
 
305
 
  inline uint32_t getCommentLength()
306
 
  {
307
 
    return (table_proto) ? table_proto->options().comment().length() : 0; 
308
 
  }
309
 
 
310
 
  inline bool hasKeyBlockSize()
311
 
  {
312
 
    return (table_proto) ? table_proto->options().has_key_block_size() : false;
313
 
  }
314
 
 
315
 
  inline uint32_t getKeyBlockSize()
316
 
  {
317
 
    return (table_proto) ? table_proto->options().key_block_size() : 0;
318
 
  }
319
 
 
320
 
  inline uint64_t getMaxRows()
321
 
  {
322
 
    return max_rows;
323
 
  }
324
 
 
325
 
  inline void setMaxRows(uint64_t arg)
326
 
  {
327
 
    max_rows= arg;
328
 
  }
329
 
 
330
 
  /**
331
 
   * Returns true if the supplied Field object
332
 
   * is part of the table's primary key.
333
 
   */
334
 
  bool fieldInPrimaryKey(Field *field) const;
335
 
 
336
 
  plugin::StorageEngine *storage_engine;                        /* storage engine plugin */
337
 
  inline plugin::StorageEngine *db_type() const /* table_type for handler */
338
 
  {
339
 
    return storage_engine;
340
 
  }
341
 
  inline plugin::StorageEngine *getEngine() const       /* table_type for handler */
342
 
  {
343
 
    return storage_engine;
344
 
  }
345
 
 
346
 
  TableIdentifier::Type tmp_table;
347
 
 
348
 
  uint32_t ref_count;       /* How many Table objects uses this */
349
 
  uint32_t getTableCount()
350
 
  {
351
 
    return ref_count;
352
 
  }
353
 
 
354
 
  uint32_t null_bytes;
355
 
  uint32_t last_null_bit_pos;
356
 
  uint32_t fields;                              /* Number of fields */
357
 
  uint32_t rec_buff_length;                 /* Size of table->record[] buffer */
358
 
  uint32_t keys, key_parts;
359
 
  uint32_t max_key_length, max_unique_length, total_key_length;
360
 
  uint32_t uniques;                         /* Number of UNIQUE index */
361
 
  uint32_t null_fields;                 /* number of null fields */
362
 
  uint32_t blob_fields;                 /* number of blob fields */
363
 
  uint32_t timestamp_field_offset;              /* Field number for timestamp field */
364
 
  uint32_t varchar_fields;                  /* number of varchar fields */
365
 
  uint32_t db_create_options;           /* Create options from database */
366
 
  uint32_t db_options_in_use;           /* Options in use */
367
 
  uint32_t db_record_offset;            /* if HA_REC_IN_SEQ */
368
 
  uint32_t rowid_field_offset;          /* Field_nr +1 to rowid field */
369
 
  /**
370
 
   * @TODO 
371
 
   *
372
 
   * Currently the replication services component uses
373
 
   * the primary_key member to determine which field is the table's
374
 
   * primary key.  However, as it exists, because this member is scalar, it
375
 
   * only supports a single-column primary key. Is there a better way
376
 
   * to ask for the fields which are in a primary key?
377
 
   */
378
 
  uint32_t primary_key;
379
 
  /* Index of auto-updated TIMESTAMP field in field array */
380
 
  uint32_t next_number_index;               /* autoincrement key number */
381
 
  uint32_t next_number_key_offset;          /* autoinc keypart offset in a key */
382
 
  uint32_t next_number_keypart;             /* autoinc keypart number in a key */
383
 
  uint32_t error, open_errno, errarg;       /* error from open_table_def() */
384
 
  uint32_t column_bitmap_size;
385
 
 
386
 
  uint8_t blob_ptr_size;                        /* 4 or 8 */
387
 
  bool db_low_byte_first;               /* Portable row format */
388
 
 
389
 
  bool name_lock;
390
 
  bool isNameLock() const
391
 
  {
392
 
    return name_lock;
393
 
  }
394
 
 
395
 
  bool replace_with_name_lock;
396
 
 
397
 
  bool waiting_on_cond;                 /* Protection against free */
398
 
  bool isWaitingOnCondition()
399
 
  {
400
 
    return waiting_on_cond;
401
 
  }
402
 
 
403
 
  /*
404
 
    Set of keys in use, implemented as a Bitmap.
405
 
    Excludes keys disabled by ALTER Table ... DISABLE KEYS.
406
 
  */
407
 
  key_map keys_in_use;
408
 
  key_map keys_for_keyread;
409
 
 
410
 
  /*
411
 
    Set share's table cache key and update its db and table name appropriately.
412
 
 
413
 
    SYNOPSIS
414
 
    set_table_cache_key()
415
 
    key_buff    Buffer with already built table cache key to be
416
 
    referenced from share.
417
 
    key_length  Key length.
418
 
 
419
 
    NOTES
420
 
    Since 'key_buff' buffer will be referenced from share it should has same
421
 
    life-time as share itself.
422
 
    This method automatically ensures that TableShare::table_name/db have
423
 
    appropriate values by using table cache key as their source.
424
 
  */
425
 
 
426
 
  void set_table_cache_key(char *key_buff, uint32_t key_length)
427
 
  {
428
 
    table_cache_key.str= key_buff;
429
 
    table_cache_key.length= key_length;
430
 
    /*
431
 
      Let us use the fact that the key is "db/0/table_name/0" + optional
432
 
      part for temporary tables.
433
 
    */
434
 
    db.str=            table_cache_key.str;
435
 
    db.length=         strlen(db.str);
436
 
    table_name.str=    db.str + db.length + 1;
437
 
    table_name.length= strlen(table_name.str);
438
 
  }
439
 
 
440
 
 
441
 
  /*
442
 
    Set share's table cache key and update its db and table name appropriately.
443
 
 
444
 
    SYNOPSIS
445
 
    set_table_cache_key()
446
 
    key_buff    Buffer to be used as storage for table cache key
447
 
    (should be at least key_length bytes).
448
 
    key         Value for table cache key.
449
 
    key_length  Key length.
450
 
 
451
 
    NOTE
452
 
    Since 'key_buff' buffer will be used as storage for table cache key
453
 
    it should has same life-time as share itself.
454
 
  */
455
 
 
456
 
  void set_table_cache_key(char *key_buff, const char *key, uint32_t key_length)
457
 
  {
458
 
    memcpy(key_buff, key, key_length);
459
 
    set_table_cache_key(key_buff, key_length);
460
 
  }
461
 
 
462
 
  inline bool honor_global_locks()
463
 
  {
464
 
    return (table_category == TABLE_CATEGORY_USER);
465
 
  }
466
 
 
467
 
 
468
 
  /*
469
 
    Initialize share for temporary tables
470
 
 
471
 
    SYNOPSIS
472
 
    init()
473
 
    share       Share to fill
474
 
    key         Table_cache_key, as generated from create_table_def_key.
475
 
    must start with db name.
476
 
    key_length  Length of key
477
 
    table_name  Table name
478
 
    path        Path to table (possible in lower case)
479
 
 
480
 
    NOTES
481
 
    This is different from alloc_table_share() because temporary tables
482
 
    don't have to be shared between threads or put into the table def
483
 
    cache, so we can do some things notable simpler and faster
484
 
 
485
 
    If table is not put in session->temporary_tables (happens only when
486
 
    one uses OPEN TEMPORARY) then one can specify 'db' as key and
487
 
    use key_length= 0 as neither table_cache_key or key_length will be used).
488
 
  */
489
 
 
490
 
  void init()
491
 
  {
492
 
    init("", 0, "", "");
493
 
  }
494
 
 
495
 
  void init(const char *new_table_name,
496
 
            const char *new_path)
497
 
  {
498
 
    init("", 0, new_table_name, new_path);
499
 
  }
500
 
 
501
 
  void init(const char *key,
502
 
            uint32_t key_length, const char *new_table_name,
503
 
            const char *new_path)
504
 
  {
505
 
    memset(this, 0, sizeof(TableShare));
506
 
    memory::init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
507
 
    table_category=         TABLE_CATEGORY_TEMPORARY;
508
 
    tmp_table=              message::Table::INTERNAL;
509
 
    db.str=                 (char*) key;
510
 
    db.length=           strlen(key);
511
 
    table_cache_key.str=    (char*) key;
512
 
    table_cache_key.length= key_length;
513
 
    table_name.str=         (char*) new_table_name;
514
 
    table_name.length=      strlen(new_table_name);
515
 
    path.str=               (char*) new_path;
516
 
    normalized_path.str=    (char*) new_path;
517
 
    path.length= normalized_path.length= strlen(new_path);
518
 
 
519
 
    return;
520
 
  }
521
 
 
522
 
  /*
523
 
    Free table share and memory used by it
524
 
 
525
 
    SYNOPSIS
526
 
    free_table_share()
527
 
    share               Table share
528
 
 
529
 
    NOTES
530
 
    share->mutex must be locked when we come here if it's not a temp table
531
 
  */
532
 
 
533
 
  void free_table_share()
534
 
  {
535
 
    memory::Root new_mem_root;
536
 
    assert(ref_count == 0);
537
 
 
538
 
    /*
539
 
      If someone is waiting for this to be deleted, inform it about this.
540
 
      Don't do a delete until we know that no one is refering to this anymore.
541
 
    */
542
 
    if (tmp_table == message::Table::STANDARD)
543
 
    {
544
 
      /* share->mutex is locked in release_table_share() */
545
 
      while (waiting_on_cond)
546
 
      {
547
 
        pthread_cond_broadcast(&cond);
548
 
        pthread_cond_wait(&cond, &mutex);
549
 
      }
550
 
      /* No thread refers to this anymore */
551
 
      pthread_mutex_unlock(&mutex);
552
 
      pthread_mutex_destroy(&mutex);
553
 
      pthread_cond_destroy(&cond);
554
 
    }
555
 
    hash_free(&name_hash);
556
 
 
557
 
    storage_engine= NULL;
558
 
 
559
 
    delete table_proto;
560
 
    table_proto= NULL;
561
 
 
562
 
    /* We must copy mem_root from share because share is allocated through it */
563
 
    memcpy(&new_mem_root, &mem_root, sizeof(new_mem_root));
564
 
    free_root(&new_mem_root, MYF(0));                 // Free's share
565
 
  }
566
 
 
567
 
  void open_table_error(int pass_error, int db_errno, int pass_errarg);
568
 
 
569
 
 
570
 
 
571
 
  /*
572
 
    Create a table cache key
573
 
 
574
 
    SYNOPSIS
575
 
    createKey()
576
 
    key                 Create key here (must be of size MAX_DBKEY_LENGTH)
577
 
    table_list          Table definition
578
 
 
579
 
    IMPLEMENTATION
580
 
    The table cache_key is created from:
581
 
    db_name + \0
582
 
    table_name + \0
583
 
 
584
 
    if the table is a tmp table, we add the following to make each tmp table
585
 
    unique on the slave:
586
 
 
587
 
    4 bytes for master thread id
588
 
    4 bytes pseudo thread id
589
 
 
590
 
    RETURN
591
 
    Length of key
592
 
  */
593
 
  static inline uint32_t createKey(char *key, const char *db_arg, const char *table_name_arg)
594
 
  {
595
 
    uint32_t key_length;
596
 
    char *key_pos= key;
597
 
 
598
 
    key_pos= strcpy(key_pos, db_arg) + strlen(db_arg);
599
 
    key_pos= strcpy(key_pos+1, table_name_arg) +
600
 
      strlen(table_name_arg);
601
 
    key_length= (uint32_t)(key_pos-key)+1;
602
 
 
603
 
    return key_length;
604
 
  }
605
 
 
606
 
  static inline uint32_t createKey(char *key, TableIdentifier &identifier)
607
 
  {
608
 
    uint32_t key_length;
609
 
    char *key_pos= key;
610
 
 
611
 
    key_pos= strcpy(key_pos, identifier.getSchemaName().c_str()) + identifier.getSchemaName().length();
612
 
    key_pos= strcpy(key_pos + 1, identifier.getTableName().c_str()) + identifier.getTableName().length();
613
 
    key_length= (uint32_t)(key_pos-key)+1;
614
 
 
615
 
    return key_length;
616
 
  }
617
 
 
618
 
  static void cacheStart(void);
619
 
  static void cacheStop(void);
620
 
  static void release(TableShare *share);
621
 
  static void release(const char *key, uint32_t key_length);
622
 
  static TableDefinitionCache &getCache();
623
 
  static TableShare *getShare(TableIdentifier &identifier);
624
 
  static TableShare *getShare(Session *session, 
625
 
                              TableList *table_list, char *key,
626
 
                              uint32_t key_length, uint32_t, int *error);
627
 
 
628
 
  friend std::ostream& operator<<(std::ostream& output, const TableShare &share)
629
 
  {
630
 
    output << "TableShare:(";
631
 
    output <<  share.getSchemaName();
632
 
    output << ", ";
633
 
    output << share.getTableName();
634
 
    output << ", ";
635
 
    output << share.getTableTypeAsString();
636
 
    output << ", ";
637
 
    output << share.getPath();
638
 
    output << ")";
639
 
 
640
 
    return output;  // for multiple << operators.
641
 
  }
642
 
};
643
 
 
644
 
} /* namespace drizzled */
645
 
 
646
 
#endif /* DRIZZLED_TABLE_SHARE_H */