~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzledump_mysql.cc

  • Committer: Prafulla Tekawade
  • Date: 2010-07-13 16:07:35 UTC
  • mto: (1662.1.4 rollup)
  • mto: This revision was merged to the branch mainline in revision 1664.
  • Revision ID: prafulla_t@users.sourceforge.net-20100713160735-2fsdtrm3azayuyu1
This bug is simillar to mysql bug 36133
http://bugs.mysql.com/bug.php?id=36133

Taking changes from that fix.

  - The problem was that the range optimizer evaluated constant expressions, 
    and among them it would try to evaluate IN-subquery predicates slated for
    handling with materialization strategy. However, these predicates require
    that parent_join->setup_subquery_materialization() is invoked before one
    attempts to evaluate them.
  
  - Fixed by making the range optimizer not to evaluate expressions that have
    item->is_expensive() == TRUE (these are materialization subqueries and 
    stored function calls). This should also resolve the problem that EXPLAIN 
    may be too long. 
    This change cuts off some opportunities for range optimizer, but this is 
    the price we're willing to pay for separation of query optimization and
    execution. 

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) 2010 Andrew Hutchings
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
 
 
20
 
#include "drizzledump_data.h"
21
 
#include "drizzledump_mysql.h"
22
 
#include "client_priv.h"
23
 
#include <string>
24
 
#include <iostream>
25
 
#include <boost/regex.hpp>
26
 
#include <boost/date_time/posix_time/posix_time.hpp>
27
 
#include <drizzled/gettext.h>
28
 
 
29
 
extern bool verbose;
30
 
extern bool ignore_errors;
31
 
 
32
 
bool DrizzleDumpDatabaseMySQL::populateTables()
33
 
{
34
 
  drizzle_result_st *result;
35
 
  drizzle_row_t row;
36
 
  std::string query;
37
 
 
38
 
  if (not dcon->setDB(databaseName))
39
 
    return false;
40
 
 
41
 
  if (verbose)
42
 
    std::cerr << _("-- Retrieving table structures for ") << databaseName << "..." << std::endl;
43
 
 
44
 
  query="SELECT TABLE_NAME, TABLE_COLLATION, ENGINE, AUTO_INCREMENT, TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE != 'VIEW' AND TABLE_SCHEMA='";
45
 
  query.append(databaseName);
46
 
  query.append("' ORDER BY TABLE_NAME");
47
 
 
48
 
  result= dcon->query(query);
49
 
 
50
 
  if (result == NULL)
51
 
    return false;
52
 
 
53
 
  while ((row= drizzle_row_next(result)))
54
 
  {
55
 
    size_t* row_sizes= drizzle_row_field_sizes(result);
56
 
    std::string tableName(row[0]);
57
 
    std::string displayName(tableName);
58
 
    cleanTableName(displayName);
59
 
    if (not ignoreTable(displayName))
60
 
      continue;
61
 
 
62
 
    DrizzleDumpTableMySQL *table = new DrizzleDumpTableMySQL(tableName, dcon);
63
 
    table->displayName= displayName;
64
 
    table->setCollate(row[1]);
65
 
    table->setEngine(row[2]);
66
 
    if (row[3])
67
 
      table->autoIncrement= boost::lexical_cast<uint64_t>(row[3]);
68
 
    else
69
 
      table->autoIncrement= 0;
70
 
 
71
 
    if ((row[4]) and (strstr(row[4], "InnoDB free") == NULL))
72
 
      table->comment= DrizzleDumpData::escape(row[4], row_sizes[4]);
73
 
    else
74
 
      table->comment= "";
75
 
 
76
 
    table->database= this;
77
 
    if ((not table->populateFields()) or (not table->populateIndexes()) or
78
 
     (not table->populateFkeys()))
79
 
    {
80
 
      delete table;
81
 
      if (not ignore_errors)
82
 
        return false;
83
 
      else
84
 
        continue;
85
 
    }
86
 
    tables.push_back(table);
87
 
  }
88
 
 
89
 
  dcon->freeResult(result);
90
 
 
91
 
  return true;
92
 
}
93
 
 
94
 
bool DrizzleDumpDatabaseMySQL::populateTables(const std::vector<std::string> &table_names)
95
 
{
96
 
  drizzle_result_st *result;
97
 
  drizzle_row_t row;
98
 
  std::string query;
99
 
 
100
 
  if (not dcon->setDB(databaseName))
101
 
    return false;
102
 
 
103
 
  if (verbose)
104
 
    std::cerr << _("-- Retrieving table structures for ") << databaseName << "..." << std::endl;
105
 
  for (std::vector<std::string>::const_iterator it= table_names.begin(); it != table_names.end(); ++it)
106
 
  {
107
 
    std::string tableName= *it;
108
 
    std::string displayName(tableName);
109
 
    cleanTableName(displayName);
110
 
    if (not ignoreTable(displayName))
111
 
      continue;
112
 
 
113
 
    query="SELECT TABLE_NAME, TABLE_COLLATION, ENGINE, AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='";
114
 
    query.append(databaseName);
115
 
    query.append("' AND TABLE_NAME = '");
116
 
    query.append(tableName);
117
 
    query.append("'");
118
 
 
119
 
    result= dcon->query(query);
120
 
 
121
 
    if (result == NULL)
122
 
      return false;
123
 
 
124
 
    if ((row= drizzle_row_next(result)))
125
 
    {
126
 
      DrizzleDumpTableMySQL *table = new DrizzleDumpTableMySQL(tableName, dcon);
127
 
      table->displayName= displayName;
128
 
      table->setCollate(row[1]);
129
 
      table->setEngine(row[2]);
130
 
      if (row[3])
131
 
        table->autoIncrement= boost::lexical_cast<uint64_t>(row[3]);
132
 
      else
133
 
        table->autoIncrement= 0;
134
 
 
135
 
      table->database= this;
136
 
      if ((not table->populateFields()) or (not table->populateIndexes()))
137
 
      {
138
 
        delete table;
139
 
        if (not ignore_errors)
140
 
          return false;
141
 
        else
142
 
          continue;
143
 
      }
144
 
      tables.push_back(table);
145
 
      dcon->freeResult(result);
146
 
    }
147
 
    else
148
 
    {
149
 
      dcon->freeResult(result);
150
 
      if (not ignore_errors)
151
 
        return false;
152
 
      else
153
 
        continue;
154
 
    }
155
 
  }
156
 
 
157
 
  return true;
158
 
 
159
 
}
160
 
 
161
 
bool DrizzleDumpTableMySQL::populateFields()
162
 
{
163
 
  drizzle_result_st *result;
164
 
  drizzle_row_t row;
165
 
  std::string query;
166
 
 
167
 
  if (verbose)
168
 
    std::cerr << _("-- Retrieving fields for ") << tableName << "..." << std::endl;
169
 
 
170
 
  query="SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_DEFAULT, IS_NULLABLE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, COLLATION_NAME, EXTRA, COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='";
171
 
  query.append(database->databaseName);
172
 
  query.append("' AND TABLE_NAME='");
173
 
  query.append(tableName);
174
 
  query.append("' ORDER BY ORDINAL_POSITION");
175
 
 
176
 
  result= dcon->query(query);
177
 
 
178
 
  if (result == NULL)
179
 
    return false;
180
 
 
181
 
  while ((row= drizzle_row_next(result)))
182
 
  {
183
 
    std::string fieldName(row[0]);
184
 
    DrizzleDumpFieldMySQL *field = new DrizzleDumpFieldMySQL(fieldName, dcon);
185
 
    /* Stop valgrind warning */
186
 
    field->convertDateTime= false;
187
 
    field->isNull= (strcmp(row[3], "YES") == 0) ? true : false;
188
 
    /* Also sets collation */
189
 
    field->setType(row[1], row[8]);
190
 
    if (field->type.compare("ENUM") == 0)
191
 
      field->isNull= true;
192
 
 
193
 
    if ((row[2]) and (field->type.compare("TEXT") != 0))
194
 
    {
195
 
      field->defaultValue= row[2];
196
 
      if (field->convertDateTime)
197
 
      {
198
 
        field->dateTimeConvert();
199
 
      }
200
 
    }
201
 
    else
202
 
    {
203
 
      field->defaultValue= "";
204
 
    }
205
 
 
206
 
    field->isAutoIncrement= (strcmp(row[8], "auto_increment") == 0) ? true : false;
207
 
    field->defaultIsNull= field->isNull;
208
 
 
209
 
    /* Seriously MySQL, why is BIT length in NUMERIC_PRECISION? */
210
 
    if ((strncmp(row[1], "bit", 3) == 0) and (row[5] != NULL))
211
 
      field->length= ((boost::lexical_cast<uint32_t>(row[5]) - 1) / 8) + 1;
212
 
    else
213
 
      field->length= (row[4]) ? boost::lexical_cast<uint32_t>(row[4]) : 0;
214
 
 
215
 
    /* Also, CHAR(0) is valid?? */
216
 
    if (((field->type.compare("VARBINARY") == 0) 
217
 
      or (field->type.compare("VARCHAR") == 0))
218
 
      and (field->length == 0))
219
 
    {
220
 
      field->length= 1;
221
 
    }
222
 
 
223
 
    field->decimalPrecision= (row[5]) ? boost::lexical_cast<uint32_t>(row[5]) : 0;
224
 
    field->decimalScale= (row[6]) ? boost::lexical_cast<uint32_t>(row[6]) : 0;
225
 
    field->comment= (row[9]) ? row[9] : "";
226
 
    fields.push_back(field);
227
 
  }
228
 
 
229
 
  dcon->freeResult(result);
230
 
  return true;
231
 
}
232
 
 
233
 
 
234
 
void DrizzleDumpFieldMySQL::dateTimeConvert(void)
235
 
{
236
 
  boost::match_flag_type flags = boost::match_default;
237
 
 
238
 
  if (strcmp(defaultValue.c_str(), "CURRENT_TIMESTAMP") == 0)
239
 
    return;
240
 
 
241
 
  if (type.compare("INT") == 0)
242
 
  {
243
 
    /* We were a TIME, now we are an INT */
244
 
    std::string ts(defaultValue);
245
 
    boost::posix_time::time_duration td(boost::posix_time::duration_from_string(ts));
246
 
    defaultValue= boost::lexical_cast<std::string>(td.total_seconds());
247
 
    return;
248
 
  }
249
 
 
250
 
  boost::regex date_regex("(0000|-00)");
251
 
 
252
 
  if (regex_search(defaultValue, date_regex, flags))
253
 
  {
254
 
    defaultIsNull= true;
255
 
    defaultValue="";
256
 
  }
257
 
}
258
 
 
259
 
 
260
 
bool DrizzleDumpTableMySQL::populateIndexes()
261
 
{
262
 
  drizzle_result_st *result;
263
 
  drizzle_row_t row;
264
 
  std::string query;
265
 
  std::string lastKey;
266
 
  bool firstIndex= true;
267
 
  DrizzleDumpIndex *index;
268
 
 
269
 
  if (verbose)
270
 
    std::cerr << _("-- Retrieving indexes for ") << tableName << "..." << std::endl;
271
 
 
272
 
  query="SHOW INDEXES FROM ";
273
 
  query.append(tableName);
274
 
 
275
 
  result= dcon->query(query);
276
 
 
277
 
  if (result == NULL)
278
 
    return false;
279
 
 
280
 
  while ((row= drizzle_row_next(result)))
281
 
  {
282
 
    std::string indexName(row[2]);
283
 
    if (indexName.compare(lastKey) != 0)
284
 
    {
285
 
      if (strcmp(row[10], "FULLTEXT") == 0)
286
 
        continue;
287
 
 
288
 
      if (!firstIndex)
289
 
        indexes.push_back(index);
290
 
      index = new DrizzleDumpIndexMySQL(indexName, dcon);
291
 
      index->isPrimary= (strcmp(row[2], "PRIMARY") == 0);
292
 
      index->isUnique= (strcmp(row[1], "0") == 0);
293
 
      index->isHash= (strcmp(row[10], "HASH") == 0);
294
 
      index->length= (row[7]) ? boost::lexical_cast<uint32_t>(row[7]) : 0;
295
 
      lastKey= row[2];
296
 
      firstIndex= false;
297
 
    }
298
 
    index->columns.push_back(row[4]);
299
 
  }
300
 
  if (!firstIndex)
301
 
    indexes.push_back(index);
302
 
 
303
 
  dcon->freeResult(result);
304
 
  return true;
305
 
}
306
 
 
307
 
bool DrizzleDumpTableMySQL::populateFkeys()
308
 
{
309
 
  drizzle_result_st *result;
310
 
  drizzle_row_t row;
311
 
  std::string query;
312
 
  DrizzleDumpForeignKey *fkey;
313
 
 
314
 
  if (verbose)
315
 
    std::cerr << _("-- Retrieving foreign keys for ") << tableName << "..." << std::endl;
316
 
 
317
 
  query= "SHOW CREATE TABLE `";
318
 
  query.append(database->databaseName);
319
 
  query.append("`.`");
320
 
  query.append(tableName);
321
 
  query.append("`");
322
 
  result= dcon->query(query);
323
 
 
324
 
  if (result == NULL)
325
 
    return false;
326
 
 
327
 
  if ((row= drizzle_row_next(result)))
328
 
  {
329
 
    boost::match_flag_type flags = boost::match_default;
330
 
    boost::regex constraint_regex("CONSTRAINT `(.*?)` FOREIGN KEY \\((.*?)\\) REFERENCES `(.*?)` \\((.*?)\\)( ON (UPDATE|DELETE) (CASCADE|RESTRICT|SET NULL))?( ON (UPDATE|DELETE) (CASCADE|RESTRICT|SET NULL))?");
331
 
 
332
 
    boost::match_results<std::string::const_iterator> constraint_results;
333
 
 
334
 
    std::string search_body(row[1]);
335
 
    std::string::const_iterator start, end;
336
 
    start= search_body.begin();
337
 
    end= search_body.end();
338
 
    while (regex_search(start, end, constraint_results, constraint_regex, flags))
339
 
    {
340
 
      fkey= new DrizzleDumpForeignKey(constraint_results[1], dcon);
341
 
      fkey->parentColumns= constraint_results[2];
342
 
      fkey->childTable= constraint_results[3];
343
 
      fkey->childColumns= constraint_results[4];
344
 
        
345
 
      if (constraint_results[5].compare("") != 0)
346
 
      {
347
 
        if (constraint_results[6].compare("UPDATE") == 0)
348
 
          fkey->updateRule= constraint_results[7];
349
 
        else if (constraint_results[6].compare("DELETE") == 0)
350
 
          fkey->deleteRule= constraint_results[7];
351
 
      }
352
 
      if (constraint_results[8].compare("") != 0)
353
 
      {
354
 
        if (constraint_results[9].compare("UPDATE") == 0)
355
 
          fkey->updateRule= constraint_results[10];
356
 
        else if (constraint_results[9].compare("DELETE") == 0)
357
 
          fkey->deleteRule= constraint_results[10];
358
 
      }
359
 
      fkey->matchOption= "";
360
 
 
361
 
      fkeys.push_back(fkey);
362
 
 
363
 
      start= constraint_results[0].second;
364
 
      flags |= boost::match_prev_avail; 
365
 
      flags |= boost::match_not_bob;
366
 
    }
367
 
  }
368
 
  dcon->freeResult(result);
369
 
  return true;
370
 
}
371
 
 
372
 
void DrizzleDumpFieldMySQL::setType(const char* raw_type, const char* raw_collation)
373
 
{
374
 
  std::string old_type(raw_type);
375
 
  std::string extra;
376
 
  size_t pos;
377
 
  
378
 
  if (((pos= old_type.find("(")) != std::string::npos) or
379
 
    ((pos= old_type.find(" ")) != std::string::npos))
380
 
  {
381
 
    extra= old_type.substr(pos);
382
 
    old_type.erase(pos, std::string::npos);
383
 
  }
384
 
 
385
 
  std::transform(old_type.begin(), old_type.end(), old_type.begin(), ::toupper);
386
 
  if ((old_type.find("CHAR") != std::string::npos) or 
387
 
    (old_type.find("TEXT") != std::string::npos))
388
 
    setCollate(raw_collation);
389
 
 
390
 
  if ((old_type.compare("BIGINT") == 0) and
391
 
    ((extra.find("unsigned") != std::string::npos)))
392
 
  {
393
 
    rangeCheck= true;
394
 
  }
395
 
 
396
 
  if ((old_type.compare("INT") == 0) and 
397
 
    ((extra.find("unsigned") != std::string::npos)))
398
 
  {
399
 
    type= "BIGINT";
400
 
    return;
401
 
  }
402
 
    
403
 
  if ((old_type.compare("TINYINT") == 0) or
404
 
    (old_type.compare("SMALLINT") == 0) or
405
 
    (old_type.compare("MEDIUMINT") == 0))
406
 
  {
407
 
    type= "INT";
408
 
    return;
409
 
  }
410
 
 
411
 
  if ((old_type.compare("TINYBLOB") == 0) or
412
 
    (old_type.compare("MEDIUMBLOB") == 0) or
413
 
    (old_type.compare("LONGBLOB") == 0))
414
 
  {
415
 
    type= "BLOB";
416
 
    return;
417
 
  }
418
 
 
419
 
  if ((old_type.compare("TINYTEXT") == 0) or
420
 
    (old_type.compare("MEDIUMTEXT") == 0) or
421
 
    (old_type.compare("LONGTEXT") == 0) or
422
 
    (old_type.compare("SET") == 0))
423
 
  {
424
 
    type= "TEXT";
425
 
    return;
426
 
  }
427
 
 
428
 
  if (old_type.compare("CHAR") == 0)
429
 
  {
430
 
    type= "VARCHAR";
431
 
    return;
432
 
  }
433
 
 
434
 
  if (old_type.compare("BINARY") == 0)
435
 
  {
436
 
    type= "VARBINARY";
437
 
    
438
 
    return;
439
 
  }
440
 
 
441
 
  if (old_type.compare("ENUM") == 0)
442
 
  {
443
 
    type= old_type;
444
 
    /* Strip out the braces, we add them again during output */
445
 
    enumValues= extra.substr(1, extra.length()-2);
446
 
    return;
447
 
  }
448
 
 
449
 
  if ((old_type.find("TIME") != std::string::npos) or
450
 
    (old_type.find("DATE") != std::string::npos))
451
 
  {
452
 
    /* Intended to catch TIME/DATE/TIMESTAMP/DATETIME 
453
 
       We may have a default TIME/DATE which needs converting */
454
 
    convertDateTime= true;
455
 
    isNull= true;
456
 
  }
457
 
 
458
 
  if ((old_type.compare("TIME") == 0) or (old_type.compare("YEAR") == 0))
459
 
  {
460
 
    type= "INT";
461
 
    return;
462
 
  }
463
 
 
464
 
  if (old_type.compare("FLOAT") == 0)
465
 
  {
466
 
    type= "DOUBLE";
467
 
    return;
468
 
  }
469
 
 
470
 
  if (old_type.compare("BIT") == 0)
471
 
  {
472
 
    type= "VARBINARY";
473
 
    return;
474
 
  }
475
 
 
476
 
  type= old_type;
477
 
  return;
478
 
}
479
 
 
480
 
void DrizzleDumpTableMySQL::setEngine(const char* newEngine)
481
 
{
482
 
  if ((strcmp(newEngine, "MyISAM") == 0) || (strcmp(newEngine, "MEMORY") == 0))
483
 
    engineName= "InnoDB";
484
 
  else
485
 
    engineName= newEngine; 
486
 
}
487
 
 
488
 
DrizzleDumpData* DrizzleDumpTableMySQL::getData(void)
489
 
{
490
 
  try
491
 
  {
492
 
    return new DrizzleDumpDataMySQL(this, dcon);
493
 
  }
494
 
  catch(...)
495
 
  {
496
 
    return NULL;
497
 
  }
498
 
}
499
 
 
500
 
void DrizzleDumpDatabaseMySQL::setCollate(const char* newCollate)
501
 
{
502
 
  if (newCollate)
503
 
  {
504
 
    std::string tmpCollate(newCollate);
505
 
    if (tmpCollate.find("utf8") != std::string::npos)
506
 
    {
507
 
      collate= tmpCollate;
508
 
      return;
509
 
    }
510
 
  }
511
 
  collate= "utf8_general_ci";
512
 
}
513
 
 
514
 
void DrizzleDumpTableMySQL::setCollate(const char* newCollate)
515
 
{
516
 
  if (newCollate)
517
 
  {
518
 
    std::string tmpCollate(newCollate);
519
 
    if (tmpCollate.find("utf8") != std::string::npos)
520
 
    {
521
 
      collate= tmpCollate;
522
 
      return;
523
 
    }
524
 
  }
525
 
 
526
 
  collate= "utf8_general_ci";
527
 
}
528
 
 
529
 
void DrizzleDumpFieldMySQL::setCollate(const char* newCollate)
530
 
{
531
 
  if (newCollate)
532
 
  {
533
 
    std::string tmpCollate(newCollate);
534
 
    if (tmpCollate.find("utf8") != std::string::npos)
535
 
    {
536
 
      collation= tmpCollate;
537
 
      return;
538
 
    }
539
 
  }
540
 
  collation= "utf8_general_ci";
541
 
}
542
 
 
543
 
DrizzleDumpDataMySQL::DrizzleDumpDataMySQL(DrizzleDumpTable *dataTable,
544
 
  DrizzleDumpConnection *connection)
545
 
  : DrizzleDumpData(dataTable, connection)
546
 
{
547
 
  std::string query;
548
 
  query= "SELECT * FROM `";
549
 
  query.append(table->displayName);
550
 
  query.append("`");
551
 
 
552
 
  result= dcon->query(query);
553
 
  if (result == NULL)
554
 
    throw std::exception();
555
 
}
556
 
 
557
 
DrizzleDumpDataMySQL::~DrizzleDumpDataMySQL()
558
 
{
559
 
  drizzle_result_free(result);
560
 
  delete result;
561
 
}
562
 
 
563
 
long DrizzleDumpDataMySQL::convertTime(const char* oldTime) const
564
 
{
565
 
  std::string ts(oldTime);
566
 
  boost::posix_time::time_duration td(boost::posix_time::duration_from_string(ts));
567
 
  long seconds= td.total_seconds();
568
 
  return seconds;
569
 
}
570
 
 
571
 
std::string DrizzleDumpDataMySQL::convertDate(const char* oldDate) const
572
 
{
573
 
  boost::match_flag_type flags = boost::match_default;
574
 
  std::string output;
575
 
  boost::regex date_regex("(0000|-00)");
576
 
 
577
 
  if (not regex_search(oldDate, date_regex, flags))
578
 
  {
579
 
    output.push_back('\'');
580
 
    output.append(oldDate);
581
 
    output.push_back('\'');
582
 
  }
583
 
  else
584
 
    output= "NULL";
585
 
 
586
 
  return output;
587
 
}
588
 
 
589
 
std::string DrizzleDumpDataMySQL::checkDateTime(const char* item, uint32_t field) const
590
 
{
591
 
  std::string ret;
592
 
 
593
 
  if (table->fields[field]->convertDateTime)
594
 
  {
595
 
    if (table->fields[field]->type.compare("INT") == 0)
596
 
      ret= boost::lexical_cast<std::string>(convertTime(item));
597
 
    else
598
 
      ret= convertDate(item);
599
 
  }
600
 
  return ret;
601
 
}
602