~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/table/instance/base.cc

  • Committer: Mark Atwood
  • Date: 2011-08-09 01:21:52 UTC
  • mfrom: (2380.1.2 drizzle-autoconf)
  • Revision ID: me@mark.atwood.name-20110809012152-zxq2dgan8e6nsvse
mergeĀ lp:~brianaker/drizzle/autoreconf

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
*/
26
26
 
27
27
/* Basic functions needed by many modules */
28
 
#include "config.h"
 
28
#include <config.h>
29
29
 
30
30
#include <pthread.h>
31
31
#include <float.h>
37
37
 
38
38
#include <cassert>
39
39
 
40
 
#include "drizzled/error.h"
41
 
#include "drizzled/gettext.h"
42
 
#include "drizzled/sql_base.h"
43
 
#include "drizzled/pthread_globals.h"
44
 
#include "drizzled/internal/my_pthread.h"
45
 
 
46
 
#include "drizzled/table.h"
47
 
#include "drizzled/table/shell.h"
48
 
 
49
 
#include "drizzled/session.h"
50
 
 
51
 
#include "drizzled/charset.h"
52
 
#include "drizzled/internal/m_string.h"
53
 
#include "drizzled/internal/my_sys.h"
54
 
 
55
 
#include "drizzled/item/string.h"
56
 
#include "drizzled/item/int.h"
57
 
#include "drizzled/item/decimal.h"
58
 
#include "drizzled/item/float.h"
59
 
#include "drizzled/item/null.h"
60
 
#include "drizzled/temporal.h"
61
 
 
62
 
#include "drizzled/field.h"
63
 
#include "drizzled/field/str.h"
64
 
#include "drizzled/field/num.h"
65
 
#include "drizzled/field/blob.h"
66
 
#include "drizzled/field/boolean.h"
67
 
#include "drizzled/field/enum.h"
68
 
#include "drizzled/field/null.h"
69
 
#include "drizzled/field/date.h"
70
 
#include "drizzled/field/decimal.h"
71
 
#include "drizzled/field/real.h"
72
 
#include "drizzled/field/double.h"
73
 
#include "drizzled/field/int32.h"
74
 
#include "drizzled/field/int64.h"
75
 
#include "drizzled/field/size.h"
76
 
#include "drizzled/field/num.h"
77
 
#include "drizzled/field/time.h"
78
 
#include "drizzled/field/epoch.h"
79
 
#include "drizzled/field/datetime.h"
80
 
#include "drizzled/field/microtime.h"
81
 
#include "drizzled/field/varstring.h"
82
 
#include "drizzled/field/uuid.h"
83
 
 
84
 
#include "drizzled/plugin/storage_engine.h"
85
 
 
86
 
#include "drizzled/definition/cache.h"
87
 
 
88
 
#include <drizzled/refresh_version.h>
 
40
#include <drizzled/error.h>
 
41
#include <drizzled/gettext.h>
 
42
#include <drizzled/sql_base.h>
 
43
#include <drizzled/pthread_globals.h>
 
44
#include <drizzled/internal/my_pthread.h>
 
45
 
 
46
#include <drizzled/table.h>
 
47
#include <drizzled/table/shell.h>
 
48
 
 
49
#include <drizzled/session.h>
 
50
 
 
51
#include <drizzled/charset.h>
 
52
#include <drizzled/internal/m_string.h>
 
53
#include <drizzled/internal/my_sys.h>
 
54
 
 
55
#include <drizzled/item/string.h>
 
56
#include <drizzled/item/int.h>
 
57
#include <drizzled/item/decimal.h>
 
58
#include <drizzled/item/float.h>
 
59
#include <drizzled/item/null.h>
 
60
#include <drizzled/temporal.h>
 
61
 
 
62
#include <drizzled/field.h>
 
63
#include <drizzled/field/str.h>
 
64
#include <drizzled/field/num.h>
 
65
#include <drizzled/field/blob.h>
 
66
#include <drizzled/field/boolean.h>
 
67
#include <drizzled/field/enum.h>
 
68
#include <drizzled/field/null.h>
 
69
#include <drizzled/field/date.h>
 
70
#include <drizzled/field/decimal.h>
 
71
#include <drizzled/field/real.h>
 
72
#include <drizzled/field/double.h>
 
73
#include <drizzled/field/int32.h>
 
74
#include <drizzled/field/int64.h>
 
75
#include <drizzled/field/size.h>
 
76
#include <drizzled/field/num.h>
 
77
#include <drizzled/field/time.h>
 
78
#include <drizzled/field/epoch.h>
 
79
#include <drizzled/field/datetime.h>
 
80
#include <drizzled/field/microtime.h>
 
81
#include <drizzled/field/varstring.h>
 
82
#include <drizzled/field/uuid.h>
 
83
#include <drizzled/plugin/storage_engine.h>
 
84
#include <drizzled/definition/cache.h>
 
85
#include <drizzled/typelib.h>
 
86
#include <drizzled/key.h>
 
87
#include <drizzled/open_tables_state.h>
89
88
 
90
89
using namespace std;
91
90
 
92
 
namespace drizzled
93
 
{
 
91
namespace drizzled {
94
92
 
95
93
extern size_t table_def_size;
96
94
 
97
 
 
98
95
static enum_field_types proto_field_type_to_drizzle_type(const message::Table::Field &field)
99
96
{
100
97
  switch(field.type())
146
143
}
147
144
 
148
145
static Item *default_value_item(enum_field_types field_type,
149
 
                                const CHARSET_INFO *charset,
 
146
                                const charset_info_st *charset,
150
147
                                bool default_null, const string *default_value,
151
148
                                const string *default_bin_value)
152
149
{
167
164
                                                                NULL,
168
165
                                                                &error),
169
166
                               default_value->length());
 
167
 
 
168
    if (error && error != -1) /* was an error and wasn't a negative number */
 
169
    {
 
170
      delete default_item;
 
171
      return NULL;
 
172
    }
 
173
 
170
174
    break;
171
175
  case DRIZZLE_TYPE_DOUBLE:
172
176
    default_item= new Item_float(default_value->c_str(),
248
252
  key_info(NULL),
249
253
  mem_root(TABLE_ALLOC_BLOCK_SIZE),
250
254
  all_set(),
251
 
  db(NULL_LEX_STRING),
252
 
  table_name(NULL_LEX_STRING),
253
 
  path(NULL_LEX_STRING),
254
 
  normalized_path(NULL_LEX_STRING),
 
255
  db(NULL_lex_string_t),
 
256
  table_name(NULL_lex_string_t),
 
257
  path(NULL_lex_string_t),
 
258
  normalized_path(NULL_lex_string_t),
255
259
  block_size(0),
256
260
  version(0),
257
261
  timestamp_offset(0),
293
297
{
294
298
  if (type_arg == message::Table::INTERNAL)
295
299
  {
296
 
    identifier::Table::build_tmptable_filename(private_key_for_cache.vectorPtr());
 
300
    string s= identifier::Table::build_tmptable_filename();
 
301
    private_key_for_cache.vectorPtr().assign(s.c_str(), s.c_str() + s.size() + 1);
297
302
    init(private_key_for_cache.vector(), private_key_for_cache.vector());
298
303
  }
299
304
  else
310
315
  mem_root(TABLE_ALLOC_BLOCK_SIZE),
311
316
  table_charset(0),
312
317
  all_set(),
313
 
  db(NULL_LEX_STRING),
314
 
  table_name(NULL_LEX_STRING),
315
 
  path(NULL_LEX_STRING),
316
 
  normalized_path(NULL_LEX_STRING),
 
318
  db(NULL_lex_string_t),
 
319
  table_name(NULL_lex_string_t),
 
320
  path(NULL_lex_string_t),
 
321
  normalized_path(NULL_lex_string_t),
317
322
  block_size(0),
318
323
  version(0),
319
324
  timestamp_offset(0),
370
375
  path.length= normalized_path.length= 0;
371
376
 
372
377
  std::string tb_name(identifier.getTableName());
373
 
  std::transform(tb_name.begin(), tb_name.end(), tb_name.begin(), ::tolower);
 
378
  boost::to_lower(tb_name);
374
379
  assert(strcmp(tb_name.c_str(), table_name.str) == 0);
375
 
 
376
380
  assert(strcmp(identifier.getSchemaName().c_str(), db.str) == 0);
377
381
}
378
382
 
385
389
  mem_root(TABLE_ALLOC_BLOCK_SIZE),
386
390
  table_charset(0),
387
391
  all_set(),
388
 
  db(NULL_LEX_STRING),
389
 
  table_name(NULL_LEX_STRING),
390
 
  path(NULL_LEX_STRING),
391
 
  normalized_path(NULL_LEX_STRING),
 
392
  db(NULL_lex_string_t),
 
393
  table_name(NULL_lex_string_t),
 
394
  path(NULL_lex_string_t),
 
395
  normalized_path(NULL_lex_string_t),
392
396
  block_size(0),
393
397
  version(0),
394
398
  timestamp_offset(0),
452
456
*/
453
457
TableShare::TableShare(const identifier::Table::Type type_arg,
454
458
                       const identifier::Table &identifier,
455
 
                       char *path_arg,
 
459
                       const char *path_arg,
456
460
                       uint32_t path_length_arg) :
457
461
  table_category(TABLE_UNKNOWN_CATEGORY),
458
462
  found_next_number_field(NULL),
461
465
  mem_root(TABLE_ALLOC_BLOCK_SIZE),
462
466
  table_charset(0),
463
467
  all_set(),
464
 
  db(NULL_LEX_STRING),
465
 
  table_name(NULL_LEX_STRING),
466
 
  path(NULL_LEX_STRING),
467
 
  normalized_path(NULL_LEX_STRING),
 
468
  db(NULL_lex_string_t),
 
469
  table_name(NULL_lex_string_t),
 
470
  path(NULL_lex_string_t),
 
471
  normalized_path(NULL_lex_string_t),
468
472
  block_size(0),
469
473
  version(0),
470
474
  timestamp_offset(0),
504
508
  keys_in_use(0),
505
509
  keys_for_keyread(0)
506
510
{
507
 
  char *path_buff;
 
511
 
 
512
  private_key_for_cache= identifier.getKey();
 
513
  /*
 
514
    Let us use the fact that the key is "db/0/table_name/0" + optional
 
515
    part for temporary tables.
 
516
  */
 
517
  db.str= const_cast<char *>(private_key_for_cache.vector());
 
518
  db.length=         strlen(db.str);
 
519
  table_name.str=    db.str + db.length + 1;
 
520
  table_name.length= strlen(table_name.str);
 
521
 
508
522
  std::string _path;
509
 
 
510
 
  private_key_for_cache= identifier.getKey();
511
 
  /*
512
 
    Let us use the fact that the key is "db/0/table_name/0" + optional
513
 
    part for temporary tables.
514
 
  */
515
 
  db.str= const_cast<char *>(private_key_for_cache.vector());
516
 
  db.length=         strlen(db.str);
517
 
  table_name.str=    db.str + db.length + 1;
518
 
  table_name.length= strlen(table_name.str);
519
 
 
520
523
  if (path_arg)
521
524
  {
522
 
    _path.append(path_arg, path_length_arg);
523
 
  }
524
 
  else
525
 
  {
526
 
    identifier::Table::build_table_filename(_path, db.str, table_name.str, false);
527
 
  }
528
 
 
529
 
  if ((path_buff= (char *)mem_root.alloc_root(_path.length() + 1)))
530
 
  {
531
 
    setPath(path_buff, _path.length());
532
 
    strcpy(path_buff, _path.c_str());
533
 
    setNormalizedPath(path_buff, _path.length());
534
 
 
535
 
    version= refresh_version;
536
 
  }
537
 
  else
538
 
  {
539
 
    assert(0); // We should throw here.
540
 
    abort();
541
 
  }
 
525
    _path.assign(path_arg, path_length_arg);
 
526
  }
 
527
  else
 
528
  {
 
529
    _path= identifier::Table::build_table_filename(db.str, table_name.str, false);
 
530
  }
 
531
 
 
532
  char* path_buff= mem_root.strdup(_path);
 
533
  setPath(path_buff, _path.length());
 
534
  setNormalizedPath(path_buff, _path.length());
 
535
 
 
536
  version= g_refresh_version;
542
537
}
543
538
 
544
539
void TableShare::init(const char *new_table_name,
580
575
  getTableMessage()->set_schema(identifier_arg.getSchemaName());
581
576
}
582
577
 
583
 
bool TableShare::parse_table_proto(Session& session, message::Table &table)
 
578
bool TableShare::parse_table_proto(Session& session, const message::Table &table)
584
579
{
585
580
  drizzled::error_t local_error= EE_OK;
586
581
 
614
609
  db_create_options= (local_db_create_options & 0x0000FFFF);
615
610
  db_options_in_use= db_create_options;
616
611
 
617
 
  block_size= table_options.has_block_size() ?
618
 
    table_options.block_size() : 0;
 
612
  block_size= table_options.has_block_size() ? table_options.block_size() : 0;
619
613
 
620
614
  table_charset= get_charset(table_options.collation_id());
621
615
 
636
630
  for (int indx= 0; indx < table.indexes_size(); indx++)
637
631
    key_parts+= table.indexes(indx).index_part_size();
638
632
 
639
 
  key_info= (KeyInfo*) alloc_root( table.indexes_size() * sizeof(KeyInfo) +key_parts*sizeof(KeyPartInfo));
 
633
  key_info= (KeyInfo*) alloc(table.indexes_size() * sizeof(KeyInfo) +key_parts*sizeof(KeyPartInfo));
640
634
 
641
635
  KeyPartInfo *key_part;
642
636
 
644
638
    (key_info+table.indexes_size());
645
639
 
646
640
 
647
 
  ulong *rec_per_key= (ulong*) alloc_root(sizeof(ulong*)*key_parts);
 
641
  ulong *rec_per_key= (ulong*) alloc(sizeof(ulong*)*key_parts);
648
642
 
649
643
  KeyInfo* keyinfo= key_info;
650
644
  for (int keynr= 0; keynr < table.indexes_size(); keynr++, keyinfo++)
747
741
        else
748
742
          collation_id= table.options().collation_id();
749
743
 
750
 
        const CHARSET_INFO *cs= get_charset(collation_id);
 
744
        const charset_info_st *cs= get_charset(collation_id);
751
745
 
752
746
        mbmaxlen= cs->mbmaxlen;
753
747
      }
768
762
    {
769
763
      keyinfo->flags|= HA_USES_COMMENT;
770
764
      keyinfo->comment.length= indx.comment().length();
771
 
      keyinfo->comment.str= strmake_root(indx.comment().c_str(), keyinfo->comment.length);
 
765
      keyinfo->comment.str= strdup(indx.comment().c_str(), keyinfo->comment.length);
772
766
    }
773
767
 
774
 
    keyinfo->name= strmake_root(indx.name().c_str(), indx.name().length());
 
768
    keyinfo->name= strdup(indx.name().c_str(), indx.name().length());
775
769
 
776
770
    addKeyName(string(keyinfo->name, indx.name().length()));
777
771
  }
825
819
      {
826
820
        message::Table::Field::StringFieldOptions field_options= pfield.string_options();
827
821
 
828
 
        const CHARSET_INFO *cs= get_charset(field_options.has_collation_id() ?
 
822
        const charset_info_st *cs= get_charset(field_options.has_collation_id() ?
829
823
                                            field_options.collation_id() : 0);
830
824
 
831
825
        if (! cs)
917
911
    }
918
912
 
919
913
 
920
 
    const CHARSET_INFO *charset= get_charset(field_options.has_collation_id() ?
 
914
    const charset_info_st *charset= get_charset(field_options.has_collation_id() ?
921
915
                                             field_options.collation_id() : 0);
922
916
 
923
917
    if (! charset)
925
919
 
926
920
    TYPELIB *t= (&intervals[interval_nr]);
927
921
 
928
 
    t->type_names= (const char**)alloc_root((field_options.field_value_size() + 1) * sizeof(char*));
 
922
    t->type_names= (const char**)alloc((field_options.field_value_size() + 1) * sizeof(char*));
929
923
 
930
 
    t->type_lengths= (unsigned int*) alloc_root((field_options.field_value_size() + 1) * sizeof(unsigned int));
 
924
    t->type_lengths= (unsigned int*)alloc((field_options.field_value_size() + 1) * sizeof(unsigned int));
931
925
 
932
926
    t->type_names[field_options.field_value_size()]= NULL;
933
927
    t->type_lengths[field_options.field_value_size()]= 0;
937
931
 
938
932
    for (int n= 0; n < field_options.field_value_size(); n++)
939
933
    {
940
 
      t->type_names[n]= strmake_root(field_options.field_value(n).c_str(), field_options.field_value(n).length());
 
934
      t->type_names[n]= strdup(field_options.field_value(n).c_str(), field_options.field_value(n).length());
941
935
 
942
936
      /* 
943
937
       * Go ask the charset what the length is as for "" length=1
999
993
      unireg_type= Field::TIMESTAMP_UN_FIELD;
1000
994
    }
1001
995
 
1002
 
    LEX_STRING comment;
 
996
    lex_string_t comment;
1003
997
    if (!pfield.has_comment())
1004
998
    {
1005
999
      comment.str= (char*)"";
1010
1004
      size_t len= pfield.comment().length();
1011
1005
      const char* str= pfield.comment().c_str();
1012
1006
 
1013
 
      comment.str= strmake_root(str, len);
 
1007
      comment.str= strdup(str, len);
1014
1008
      comment.length= len;
1015
1009
    }
1016
1010
 
1018
1012
 
1019
1013
    field_type= proto_field_type_to_drizzle_type(pfield);
1020
1014
 
1021
 
    const CHARSET_INFO *charset= &my_charset_bin;
 
1015
    const charset_info_st *charset= &my_charset_bin;
1022
1016
 
1023
1017
    if (field_type == DRIZZLE_TYPE_BLOB ||
1024
1018
        field_type == DRIZZLE_TYPE_VARCHAR)
1080
1074
                                        pfield.options().default_null(),
1081
1075
                                        &pfield.options().default_value(),
1082
1076
                                        &pfield.options().default_bin_value());
 
1077
      if (default_value == NULL)
 
1078
      {
 
1079
        my_error(ER_INVALID_DEFAULT, MYF(0), pfield.name().c_str());
 
1080
        return true;
 
1081
      }
1083
1082
    }
1084
1083
 
1085
1084
 
1511
1510
 
1512
1511
  NOTES
1513
1512
  This function is called when the table definition is not cached in
1514
 
  definition::Cache::singleton().getCache()
 
1513
  definition::Cache::getCache()
1515
1514
  The data is returned in 'share', which is alloced by
1516
1515
  alloc_table_share().. The code assumes that share is initialized.
1517
1516
 
1603
1602
  boost::checked_delete(outparam.cursor);
1604
1603
  outparam.cursor= 0;                           // For easier error checking
1605
1604
  outparam.db_stat= 0;
1606
 
  outparam.getMemRoot()->free_root(MYF(0));       // Safe to call on zeroed root
 
1605
  outparam.mem().free_root(MYF(0));       // Safe to call on zeroed root
1607
1606
  outparam.clearAlias();
1608
1607
 
1609
1608
  return ret;
1635
1634
 
1636
1635
  records++;
1637
1636
 
1638
 
  if (!(record= (unsigned char*) outparam.alloc_root(rec_buff_length * records)))
1639
 
    return local_error;
 
1637
  record= outparam.alloc(rec_buff_length * records);
1640
1638
 
1641
1639
  if (records == 0)
1642
1640
  {
1670
1668
    memcpy(outparam.getUpdateRecord(), getDefaultValues(), null_bytes);
1671
1669
  }
1672
1670
 
1673
 
  if (!(field_ptr = (Field **) outparam.alloc_root( (uint32_t) ((_field_size+1)* sizeof(Field*)))))
1674
 
  {
1675
 
    return local_error;
1676
 
  }
 
1671
  field_ptr = new (outparam.mem()) Field*[_field_size + 1];
1677
1672
 
1678
1673
  outparam.setFields(field_ptr);
1679
1674
 
1680
 
  record= (unsigned char*) outparam.getInsertRecord()-1;        /* Fieldstart = 1 */
 
1675
  record= outparam.getInsertRecord()-1; /* Fieldstart = 1 */
1681
1676
 
1682
1677
  outparam.null_flags= (unsigned char*) record+1;
1683
1678
 
1684
1679
  /* Setup copy of fields from share, but use the right alias and record */
1685
1680
  for (uint32_t i= 0 ; i < _field_size; i++, field_ptr++)
1686
1681
  {
1687
 
    if (!((*field_ptr)= _fields[i]->clone(outparam.getMemRoot(), &outparam)))
 
1682
    if (!((*field_ptr)= _fields[i]->clone(&outparam.mem(), &outparam)))
1688
1683
      return local_error;
1689
1684
  }
1690
 
  (*field_ptr)= 0;                              // End marker
 
1685
  *field_ptr= 0;                              // End marker
1691
1686
 
1692
1687
  if (found_next_number_field)
1693
1688
    outparam.found_next_number_field=
1702
1697
    KeyPartInfo *key_part;
1703
1698
    uint32_t n_length;
1704
1699
    n_length= keys*sizeof(KeyInfo) + key_parts*sizeof(KeyPartInfo);
1705
 
    if (!(local_key_info= (KeyInfo*) outparam.alloc_root(n_length)))
1706
 
      return local_error;
 
1700
    local_key_info= (KeyInfo*) outparam.alloc(n_length);
1707
1701
    outparam.key_info= local_key_info;
1708
1702
    key_part= (reinterpret_cast<KeyPartInfo*> (local_key_info+keys));
1709
1703
 
1733
1727
            We are using only a prefix of the column as a key:
1734
1728
            Create a new field for the key part that matches the index
1735
1729
          */
1736
 
          local_field= key_part->field= local_field->new_field(outparam.getMemRoot(), &outparam, 0);
 
1730
          local_field= key_part->field= local_field->new_field(&outparam.mem(), &outparam, 0);
1737
1731
          local_field->field_length= key_part->length;
1738
1732
        }
1739
1733
      }
1869
1863
                              unsigned char null_bit,
1870
1864
                              uint8_t decimals,
1871
1865
                              enum_field_types field_type,
1872
 
                              const CHARSET_INFO * field_charset,
 
1866
                              const charset_info_st * field_charset,
1873
1867
                              Field::utype unireg_check,
1874
1868
                              TYPELIB *interval,
1875
1869
                              const char *field_name)
1897
1891
                              unsigned char null_bit,
1898
1892
                              uint8_t decimals,
1899
1893
                              enum_field_types field_type,
1900
 
                              const CHARSET_INFO * field_charset,
 
1894
                              const charset_info_st * field_charset,
1901
1895
                              Field::utype unireg_check,
1902
1896
                              TYPELIB *interval,
1903
1897
                              const char *field_name, 
1913
1907
    null_bit= ((unsigned char) 1) << null_bit;
1914
1908
  }
1915
1909
 
1916
 
  switch (field_type) 
1917
 
  {
1918
 
  case DRIZZLE_TYPE_DATE:
1919
 
  case DRIZZLE_TYPE_DATETIME:
1920
 
  case DRIZZLE_TYPE_UUID:
1921
 
    field_charset= &my_charset_bin;
1922
 
  default: break;
1923
 
  }
1924
 
 
1925
1910
  switch (field_type)
1926
1911
  {
1927
1912
  case DRIZZLE_TYPE_ENUM:
2022
2007
                                       field_length,
2023
2008
                                       null_pos,
2024
2009
                                       null_bit,
2025
 
                                       field_name,
2026
 
                                       field_charset);
 
2010
                                       field_name);
2027
2011
  case DRIZZLE_TYPE_DATE:
2028
2012
    return new (&mem_root) Field_date(ptr,
2029
2013
                                 null_pos,
2030
2014
                                 null_bit,
2031
 
                                 field_name,
2032
 
                                 field_charset);
 
2015
                                 field_name);
2033
2016
  case DRIZZLE_TYPE_DATETIME:
2034
2017
    return new (&mem_root) Field_datetime(ptr,
2035
2018
                                     null_pos,
2036
2019
                                     null_bit,
2037
 
                                     field_name,
2038
 
                                     field_charset);
 
2020
                                     field_name);
2039
2021
  case DRIZZLE_TYPE_NULL:
2040
2022
    return new (&mem_root) Field_null(ptr,
2041
 
                                 field_length,
2042
 
                                 field_name,
2043
 
                                 field_charset);
 
2023
                                      field_length,
 
2024
                                      field_name);
2044
2025
  }
2045
2026
  assert(0);
2046
2027
  abort();
2048
2029
 
2049
2030
void TableShare::refreshVersion()
2050
2031
{
2051
 
  version= refresh_version;
 
2032
  version= g_refresh_version;
2052
2033
}
2053
2034
 
2054
2035