~ubuntu-branches/ubuntu/trusty/mysql-5.6/trusty

« back to all changes in this revision

Viewing changes to storage/ndb/tools/restore/consumer_restore.cpp

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-02-12 11:54:27 UTC
  • Revision ID: package-import@ubuntu.com-20140212115427-oq6tfsqxl1wuwehi
Tags: upstream-5.6.15
ImportĀ upstreamĀ versionĀ 5.6.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
 
3
 
 
4
   This program is free software; you can redistribute it and/or modify
 
5
   it under the terms of the GNU General Public License as published by
 
6
   the Free Software Foundation; version 2 of the License.
 
7
 
 
8
   This program is distributed in the hope that it will be useful,
 
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
   GNU General Public License for more details.
 
12
 
 
13
   You should have received a copy of the GNU General Public License
 
14
   along with this program; if not, write to the Free Software
 
15
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
 
16
*/
 
17
 
 
18
#include <NDBT_ReturnCodes.h>
 
19
#include "consumer_restore.hpp"
 
20
#include <kernel/ndb_limits.h>
 
21
#include <my_sys.h>
 
22
#include <NdbSleep.h>
 
23
#include <NdbTick.h>
 
24
#include <Properties.hpp>
 
25
#include <NdbTypesUtil.hpp>
 
26
 
 
27
#include <ndb_internal.hpp>
 
28
#include <ndb_logevent.h>
 
29
#include "../src/ndbapi/NdbDictionaryImpl.hpp"
 
30
 
 
31
#define NDB_ANYVALUE_FOR_NOLOGGING 0x8000007f
 
32
 
 
33
extern FilteredNdbOut err;
 
34
extern FilteredNdbOut info;
 
35
extern FilteredNdbOut debug;
 
36
 
 
37
static void callback(int, NdbTransaction*, void*);
 
38
static Uint32 get_part_id(const NdbDictionary::Table *table,
 
39
                          Uint32 hash_value);
 
40
 
 
41
extern BaseString g_options;
 
42
extern unsigned int opt_no_binlog;
 
43
extern bool ga_skip_broken_objects;
 
44
 
 
45
extern Properties g_rewrite_databases;
 
46
 
 
47
bool BackupRestore::m_preserve_trailing_spaces = false;
 
48
 
 
49
// ----------------------------------------------------------------------
 
50
// conversion handlers
 
51
// ----------------------------------------------------------------------
 
52
 
 
53
void *
 
54
BackupRestore::convert_bitset(const void *source,
 
55
                              void *target,
 
56
                              bool &truncated)
 
57
{
 
58
  if (!source || !target)
 
59
    return NULL;
 
60
 
 
61
  // shortcuts
 
62
  const unsigned char * const s = (const unsigned char *)source;
 
63
  char_n_padding_struct * const t = (char_n_padding_struct *)target;
 
64
 
 
65
  // write data
 
66
  if (t->n_new >= t->n_old)
 
67
  {
 
68
    // clear all bits
 
69
    memset(t->new_row, 0, t->n_new);
 
70
 
 
71
    memcpy(t->new_row, s, t->n_old);
 
72
    truncated = false;
 
73
  } else {
 
74
    // set all bits, for parity with replication's demotion semantics
 
75
    memset(t->new_row, 0xFF, t->n_new);
 
76
    truncated = true;
 
77
  }
 
78
 
 
79
  return t->new_row;
 
80
}
 
81
 
 
82
template< typename S, typename T >
 
83
void *
 
84
BackupRestore::convert_array(const void * source,
 
85
                             void * target,
 
86
                             bool & truncated)
 
87
{
 
88
  if (!source || !target)
 
89
    return NULL;
 
90
 
 
91
  // shortcuts (note that all S::... and T::... are compile-time expr)
 
92
  const unsigned char * const s = (const unsigned char *)source;
 
93
  char_n_padding_struct * const t = (char_n_padding_struct *)target;
 
94
  const Uint32 s_prefix_length = S::lengthPrefixSize();
 
95
  const Uint32 t_prefix_length = T::lengthPrefixSize();
 
96
 
 
97
  // read and adjust length
 
98
  Uint32 length = (S::isFixedSized() ? t->n_old : S::readLengthPrefix(s));
 
99
  const Uint32 max_length = t->n_new - t_prefix_length;
 
100
  if (S::isFixedSized() && !m_preserve_trailing_spaces) {
 
101
    const char s_padding_char = (S::isBinary() ? 0x00 : ' ');
 
102
    // ignore padding chars for data copying or truncation reporting
 
103
    while (length > 0 && s[length - 1] == s_padding_char) {
 
104
      length--;
 
105
    }
 
106
  }
 
107
  if (length <= max_length) {
 
108
    truncated = false;
 
109
  } else {
 
110
    length = max_length;
 
111
    truncated = true;
 
112
  }
 
113
 
 
114
  // write length prefix
 
115
  if (!T::isFixedSized()) {
 
116
    T::writeLengthPrefix(t->new_row, length);
 
117
  }
 
118
 
 
119
  // write data
 
120
  memcpy(t->new_row + t_prefix_length, s + s_prefix_length, length);
 
121
 
 
122
  // write padding
 
123
  if (T::isFixedSized()) {
 
124
    const char t_padding_char = (T::isBinary() ? 0x00 : ' ');
 
125
    const Uint32 l = max_length - length;
 
126
    memset(t->new_row + t_prefix_length + length, t_padding_char, l);
 
127
  }
 
128
 
 
129
  return t->new_row;
 
130
}
 
131
 
 
132
template< typename S, typename T >
 
133
void *
 
134
BackupRestore::convert_integral(const void * source,
 
135
                                void * target,
 
136
                                bool & truncated)
 
137
{
 
138
  if (!source || !target)
 
139
    return NULL;
 
140
 
 
141
  // read the source value
 
142
  typename S::DomainT s;
 
143
  S::load(&s, (char *)source);
 
144
 
 
145
  // Note: important to correctly handle mixed signedness comparisons.
 
146
  //
 
147
  // The problem: A straight-forward approach to convert value 's' into
 
148
  // type 'T' might be to check into which of these subranges 's' falls
 
149
  //    ... < T's lower bound <= ... <= T's upper bound < ...
 
150
  // However, this approach is _incorrect_ when applied to generic code
 
151
  //    if (s < T::lowest()) ... else if (s > T::highest()) ... else ...
 
152
  // since 'S' and 'T' may be types of different signedness.
 
153
  //
 
154
  // Under ansi (and even more K&R) C promotion rules, if 'T' is unsigned
 
155
  // and if there's no larger signed type available, the value 's' gets
 
156
  // promoted to unsigned; then, a negative value of 's' becomes (large)
 
157
  // positive -- with a wrong comparison outcome.
 
158
  //
 
159
  // Furthermore, the code should not trigger compiler warnings for any
 
160
  // selection of integral types 'S', 'T' ("mixed signedness comparison",
 
161
  // "comparison of unsigned expression <0 / >=0 is always false/true").
 
162
  //
 
163
  // The correct approach: do lower bound comparisons on signed types and
 
164
  // upper bound comparisons on unsigned types only; this requires casts.
 
165
  // For the casts to be safe, compare the value against the zero literal
 
166
  //    if (s <= 0) { check as signed } else { check as unsigned }
 
167
  // which is a valid + nontrivial test for signed and unsigned types.
 
168
  //
 
169
  // This implies that correct, generic conversion code must test into
 
170
  // which of these _four_ subranges value 's' falls
 
171
  //    ... < T's lower bound <= ... <= 0 < ... <= T's upper bound < ...
 
172
  // while handling 's' as signed/unsigned where less-equal/greater zero.
 
173
  //
 
174
  // Obviously, simplifications are possible if 'S' is unsigned or known
 
175
  // to be a subset of 'T'.  This can be accomplished by a few additional
 
176
  // compile-time expression tests, which allow code optimization to
 
177
  // issue fewer checks for certain specializations of types 'S' and 'T'.
 
178
 
 
179
  // write the target value
 
180
  typename T::DomainT t;
 
181
  if (s <= 0) {
 
182
 
 
183
    // check value against lower bound as _signed_, safe since all <= 0
 
184
    assert(S::lowest() <= 0 && T::lowest() <= 0 && s <= 0);
 
185
    const typename S::SignedT s_l_s = S::asSigned(S::lowest());
 
186
    const typename T::SignedT t_l_s = T::asSigned(T::lowest());
 
187
    const typename S::SignedT s_s = S::asSigned(s);
 
188
    if ((s_l_s < t_l_s)      // compile-time expr
 
189
        && (s_s < t_l_s)) {  // lower bound check
 
190
      t = T::lowest();
 
191
      truncated = true;
 
192
    } else {                 // within both bounds
 
193
      t = static_cast< typename T::DomainT >(s);
 
194
      truncated = false;
 
195
    }
 
196
 
 
197
  } else { // (s > 0)
 
198
 
 
199
    // check value against upper bound as _unsigned_, safe since all > 0
 
200
    assert(S::highest() > 0 && T::highest() > 0 && s > 0);
 
201
    const typename S::UnsignedT s_h_u = S::asUnsigned(S::highest());
 
202
    const typename T::UnsignedT t_h_u = T::asUnsigned(T::highest());
 
203
    const typename S::UnsignedT s_u = S::asUnsigned(s);
 
204
    if ((s_h_u > t_h_u)      // compile-time expr
 
205
        && (s_u > t_h_u)) {  // upper bound check
 
206
      t = T::highest();
 
207
      truncated = true;
 
208
    } else {                 // within both bounds
 
209
      t = static_cast< typename T::DomainT >(s);
 
210
      truncated = false;
 
211
    }
 
212
 
 
213
  }
 
214
  T::store((char *)target, &t);
 
215
 
 
216
  return target;
 
217
}
 
218
 
 
219
// ----------------------------------------------------------------------
 
220
// conversion rules
 
221
// ----------------------------------------------------------------------
 
222
 
 
223
const PromotionRules 
 
224
BackupRestore::m_allowed_promotion_attrs[] = {
 
225
  // bitset promotions/demotions
 
226
  {NDBCOL::Bit,            NDBCOL::Bit,            check_compat_sizes,
 
227
   convert_bitset},
 
228
 
 
229
  // char array promotions/demotions
 
230
  {NDBCOL::Char,           NDBCOL::Char,           check_compat_sizes,
 
231
   convert_array< Hchar, Hchar >},
 
232
  {NDBCOL::Char,           NDBCOL::Varchar,        check_compat_sizes,
 
233
   convert_array< Hchar, Hvarchar >},
 
234
  {NDBCOL::Char,           NDBCOL::Longvarchar,    check_compat_sizes,
 
235
   convert_array< Hchar, Hlongvarchar >},
 
236
  {NDBCOL::Varchar,        NDBCOL::Char,           check_compat_sizes,
 
237
   convert_array< Hvarchar, Hchar >},
 
238
  {NDBCOL::Varchar,        NDBCOL::Varchar,        check_compat_sizes,
 
239
   convert_array< Hvarchar, Hvarchar >},
 
240
  {NDBCOL::Varchar,        NDBCOL::Longvarchar,    check_compat_sizes,
 
241
   convert_array< Hvarchar, Hlongvarchar >},
 
242
  {NDBCOL::Longvarchar,    NDBCOL::Char,           check_compat_sizes,
 
243
   convert_array< Hlongvarchar, Hchar >},
 
244
  {NDBCOL::Longvarchar,    NDBCOL::Varchar,        check_compat_sizes,
 
245
   convert_array< Hlongvarchar, Hvarchar >},
 
246
  {NDBCOL::Longvarchar,    NDBCOL::Longvarchar,    check_compat_sizes,
 
247
   convert_array< Hlongvarchar, Hlongvarchar >},
 
248
 
 
249
  // binary array promotions/demotions
 
250
  {NDBCOL::Binary,         NDBCOL::Binary,         check_compat_sizes,
 
251
   convert_array< Hbinary, Hbinary >},
 
252
  {NDBCOL::Binary,         NDBCOL::Varbinary,      check_compat_sizes,
 
253
   convert_array< Hbinary, Hvarbinary >},
 
254
  {NDBCOL::Binary,         NDBCOL::Longvarbinary,  check_compat_sizes,
 
255
   convert_array< Hbinary, Hlongvarbinary >},
 
256
  {NDBCOL::Varbinary,      NDBCOL::Binary,         check_compat_sizes,
 
257
   convert_array< Hvarbinary, Hbinary >},
 
258
  {NDBCOL::Varbinary,      NDBCOL::Varbinary,      check_compat_sizes,
 
259
   convert_array< Hvarbinary, Hvarbinary >},
 
260
  {NDBCOL::Varbinary,      NDBCOL::Longvarbinary,  check_compat_sizes,
 
261
   convert_array< Hvarbinary, Hlongvarbinary >},
 
262
  {NDBCOL::Longvarbinary,  NDBCOL::Binary,         check_compat_sizes,
 
263
   convert_array< Hlongvarbinary, Hbinary >},
 
264
  {NDBCOL::Longvarbinary,  NDBCOL::Varbinary,      check_compat_sizes,
 
265
   convert_array< Hlongvarbinary, Hvarbinary >},
 
266
  {NDBCOL::Longvarbinary,  NDBCOL::Longvarbinary,  check_compat_sizes,
 
267
   convert_array< Hlongvarbinary, Hlongvarbinary >},
 
268
 
 
269
  // integral promotions
 
270
  {NDBCOL::Tinyint,        NDBCOL::Smallint,       check_compat_promotion,
 
271
   convert_integral< Hint8, Hint16>},
 
272
  {NDBCOL::Tinyint,        NDBCOL::Mediumint,      check_compat_promotion,
 
273
   convert_integral< Hint8, Hint24>},
 
274
  {NDBCOL::Tinyint,        NDBCOL::Int,            check_compat_promotion,
 
275
   convert_integral< Hint8, Hint32>},
 
276
  {NDBCOL::Tinyint,        NDBCOL::Bigint,         check_compat_promotion,
 
277
   convert_integral< Hint8, Hint64>},
 
278
  {NDBCOL::Smallint,       NDBCOL::Mediumint,      check_compat_promotion,
 
279
   convert_integral< Hint16, Hint24>},
 
280
  {NDBCOL::Smallint,       NDBCOL::Int,            check_compat_promotion,
 
281
   convert_integral< Hint16, Hint32>},
 
282
  {NDBCOL::Smallint,       NDBCOL::Bigint,         check_compat_promotion,
 
283
   convert_integral< Hint16, Hint64>},
 
284
  {NDBCOL::Mediumint,      NDBCOL::Int,            check_compat_promotion,
 
285
   convert_integral< Hint24, Hint32>},
 
286
  {NDBCOL::Mediumint,      NDBCOL::Bigint,         check_compat_promotion,
 
287
   convert_integral< Hint24, Hint64>},
 
288
  {NDBCOL::Int,            NDBCOL::Bigint,         check_compat_promotion,
 
289
   convert_integral< Hint32, Hint64>},
 
290
  {NDBCOL::Tinyunsigned,   NDBCOL::Smallunsigned,  check_compat_promotion,
 
291
   convert_integral< Huint8, Huint16>},
 
292
  {NDBCOL::Tinyunsigned,   NDBCOL::Mediumunsigned, check_compat_promotion,
 
293
   convert_integral< Huint8, Huint24>},
 
294
  {NDBCOL::Tinyunsigned,   NDBCOL::Unsigned,       check_compat_promotion,
 
295
   convert_integral< Huint8, Huint32>},
 
296
  {NDBCOL::Tinyunsigned,   NDBCOL::Bigunsigned,    check_compat_promotion,
 
297
   convert_integral< Huint8, Huint64>},
 
298
  {NDBCOL::Smallunsigned,  NDBCOL::Mediumunsigned, check_compat_promotion,
 
299
   convert_integral< Huint16, Huint24>},
 
300
  {NDBCOL::Smallunsigned,  NDBCOL::Unsigned,       check_compat_promotion,
 
301
   convert_integral< Huint16, Huint32>},
 
302
  {NDBCOL::Smallunsigned,  NDBCOL::Bigunsigned,    check_compat_promotion,
 
303
   convert_integral< Huint16, Huint64>},
 
304
  {NDBCOL::Mediumunsigned, NDBCOL::Unsigned,       check_compat_promotion,
 
305
   convert_integral< Huint24, Huint32>},
 
306
  {NDBCOL::Mediumunsigned, NDBCOL::Bigunsigned,    check_compat_promotion,
 
307
   convert_integral< Huint24, Huint64>},
 
308
  {NDBCOL::Unsigned,       NDBCOL::Bigunsigned,    check_compat_promotion,
 
309
   convert_integral< Huint32, Huint64>},
 
310
 
 
311
  // integral demotions
 
312
  {NDBCOL::Smallint,       NDBCOL::Tinyint,        check_compat_lossy,
 
313
   convert_integral< Hint16, Hint8>},
 
314
  {NDBCOL::Mediumint,      NDBCOL::Tinyint,        check_compat_lossy,
 
315
   convert_integral< Hint24, Hint8>},
 
316
  {NDBCOL::Mediumint,      NDBCOL::Smallint,       check_compat_lossy,
 
317
   convert_integral< Hint24, Hint16>},
 
318
  {NDBCOL::Int,            NDBCOL::Tinyint,        check_compat_lossy,
 
319
   convert_integral< Hint32, Hint8>},
 
320
  {NDBCOL::Int,            NDBCOL::Smallint,       check_compat_lossy,
 
321
   convert_integral< Hint32, Hint16>},
 
322
  {NDBCOL::Int,            NDBCOL::Mediumint,      check_compat_lossy,
 
323
   convert_integral< Hint32, Hint24>},
 
324
  {NDBCOL::Bigint,         NDBCOL::Tinyint,        check_compat_lossy,
 
325
   convert_integral< Hint64, Hint8>},
 
326
  {NDBCOL::Bigint,         NDBCOL::Smallint,       check_compat_lossy,
 
327
   convert_integral< Hint64, Hint16>},
 
328
  {NDBCOL::Bigint,         NDBCOL::Mediumint,      check_compat_lossy,
 
329
   convert_integral< Hint64, Hint24>},
 
330
  {NDBCOL::Bigint,         NDBCOL::Int,            check_compat_lossy,
 
331
   convert_integral< Hint64, Hint32>},
 
332
  {NDBCOL::Smallunsigned,  NDBCOL::Tinyunsigned,   check_compat_lossy,
 
333
   convert_integral< Huint16, Huint8>},
 
334
  {NDBCOL::Mediumunsigned, NDBCOL::Tinyunsigned,   check_compat_lossy,
 
335
   convert_integral< Huint24, Huint8>},
 
336
  {NDBCOL::Mediumunsigned, NDBCOL::Smallunsigned,  check_compat_lossy,
 
337
   convert_integral< Huint24, Huint16>},
 
338
  {NDBCOL::Unsigned,       NDBCOL::Tinyunsigned,   check_compat_lossy,
 
339
   convert_integral< Huint32, Huint8>},
 
340
  {NDBCOL::Unsigned,       NDBCOL::Smallunsigned,  check_compat_lossy,
 
341
   convert_integral< Huint32, Huint16>},
 
342
  {NDBCOL::Unsigned,       NDBCOL::Mediumunsigned, check_compat_lossy,
 
343
   convert_integral< Huint32, Huint24>},
 
344
  {NDBCOL::Bigunsigned,    NDBCOL::Tinyunsigned,   check_compat_lossy,
 
345
   convert_integral< Huint64, Huint8>},
 
346
  {NDBCOL::Bigunsigned,    NDBCOL::Smallunsigned,  check_compat_lossy,
 
347
   convert_integral< Huint64, Huint16>},
 
348
  {NDBCOL::Bigunsigned,    NDBCOL::Mediumunsigned, check_compat_lossy,
 
349
   convert_integral< Huint64, Huint24>},
 
350
  {NDBCOL::Bigunsigned,    NDBCOL::Unsigned,       check_compat_lossy,
 
351
   convert_integral< Huint64, Huint32>},
 
352
 
 
353
  // integral signedness conversions
 
354
  {NDBCOL::Tinyint,        NDBCOL::Tinyunsigned,   check_compat_lossy,
 
355
   convert_integral< Hint8, Huint8>},
 
356
  {NDBCOL::Smallint,       NDBCOL::Smallunsigned,  check_compat_lossy,
 
357
   convert_integral< Hint16, Huint16>},
 
358
  {NDBCOL::Mediumint,      NDBCOL::Mediumunsigned, check_compat_lossy,
 
359
   convert_integral< Hint24, Huint24>},
 
360
  {NDBCOL::Int,            NDBCOL::Unsigned,       check_compat_lossy,
 
361
   convert_integral< Hint32, Huint32>},
 
362
  {NDBCOL::Bigint,         NDBCOL::Bigunsigned,    check_compat_lossy,
 
363
   convert_integral< Hint64, Huint64>},
 
364
  {NDBCOL::Tinyunsigned,   NDBCOL::Tinyint,        check_compat_lossy,
 
365
   convert_integral< Huint8, Hint8>},
 
366
  {NDBCOL::Smallunsigned,  NDBCOL::Smallint,       check_compat_lossy,
 
367
   convert_integral< Huint16, Hint16>},
 
368
  {NDBCOL::Mediumunsigned, NDBCOL::Mediumint,      check_compat_lossy,
 
369
   convert_integral< Huint24, Hint24>},
 
370
  {NDBCOL::Unsigned,       NDBCOL::Int,            check_compat_lossy,
 
371
   convert_integral< Huint32, Hint32>},
 
372
  {NDBCOL::Bigunsigned,    NDBCOL::Bigint,         check_compat_lossy,
 
373
   convert_integral< Huint64, Hint64>},
 
374
 
 
375
  // integral signedness+promotion conversions
 
376
  {NDBCOL::Tinyint,        NDBCOL::Smallunsigned,  check_compat_lossy,
 
377
   convert_integral< Hint8, Huint16>},
 
378
  {NDBCOL::Tinyint,        NDBCOL::Mediumunsigned, check_compat_lossy,
 
379
   convert_integral< Hint8, Huint24>},
 
380
  {NDBCOL::Tinyint,        NDBCOL::Unsigned,       check_compat_lossy,
 
381
   convert_integral< Hint8, Huint32>},
 
382
  {NDBCOL::Tinyint,        NDBCOL::Bigunsigned,    check_compat_lossy,
 
383
   convert_integral< Hint8, Huint64>},
 
384
  {NDBCOL::Smallint,       NDBCOL::Mediumunsigned, check_compat_lossy,
 
385
   convert_integral< Hint16, Huint24>},
 
386
  {NDBCOL::Smallint,       NDBCOL::Unsigned,       check_compat_lossy,
 
387
   convert_integral< Hint16, Huint32>},
 
388
  {NDBCOL::Smallint,       NDBCOL::Bigunsigned,    check_compat_lossy,
 
389
   convert_integral< Hint16, Huint64>},
 
390
  {NDBCOL::Mediumint,      NDBCOL::Unsigned,       check_compat_lossy,
 
391
   convert_integral< Hint24, Huint32>},
 
392
  {NDBCOL::Mediumint,      NDBCOL::Bigunsigned,    check_compat_lossy,
 
393
   convert_integral< Hint24, Huint64>},
 
394
  {NDBCOL::Int,            NDBCOL::Bigunsigned,    check_compat_lossy,
 
395
   convert_integral< Hint32, Huint64>},
 
396
  {NDBCOL::Tinyunsigned,   NDBCOL::Smallint,       check_compat_lossy,
 
397
   convert_integral< Huint8, Hint16>},
 
398
  {NDBCOL::Tinyunsigned,   NDBCOL::Mediumint,      check_compat_lossy,
 
399
   convert_integral< Huint8, Hint24>},
 
400
  {NDBCOL::Tinyunsigned,   NDBCOL::Int,            check_compat_lossy,
 
401
   convert_integral< Huint8, Hint32>},
 
402
  {NDBCOL::Tinyunsigned,   NDBCOL::Bigint,         check_compat_lossy,
 
403
   convert_integral< Huint8, Hint64>},
 
404
  {NDBCOL::Smallunsigned,  NDBCOL::Mediumint,      check_compat_lossy,
 
405
   convert_integral< Huint16, Hint24>},
 
406
  {NDBCOL::Smallunsigned,  NDBCOL::Int,            check_compat_lossy,
 
407
   convert_integral< Huint16, Hint32>},
 
408
  {NDBCOL::Smallunsigned,  NDBCOL::Bigint,         check_compat_lossy,
 
409
   convert_integral< Huint16, Hint64>},
 
410
  {NDBCOL::Mediumunsigned, NDBCOL::Int,            check_compat_lossy,
 
411
   convert_integral< Huint24, Hint32>},
 
412
  {NDBCOL::Mediumunsigned, NDBCOL::Bigint,         check_compat_lossy,
 
413
   convert_integral< Huint24, Hint64>},
 
414
  {NDBCOL::Unsigned,       NDBCOL::Bigint,         check_compat_lossy,
 
415
   convert_integral< Huint32, Hint64>},
 
416
 
 
417
  // integral signedness+demotion conversions
 
418
  {NDBCOL::Smallint,       NDBCOL::Tinyunsigned,   check_compat_lossy,
 
419
   convert_integral< Hint16, Huint8>},
 
420
  {NDBCOL::Mediumint,      NDBCOL::Tinyunsigned,   check_compat_lossy,
 
421
   convert_integral< Hint24, Huint8>},
 
422
  {NDBCOL::Mediumint,      NDBCOL::Smallunsigned,  check_compat_lossy,
 
423
   convert_integral< Hint24, Huint16>},
 
424
  {NDBCOL::Int,            NDBCOL::Tinyunsigned,   check_compat_lossy,
 
425
   convert_integral< Hint32, Huint8>},
 
426
  {NDBCOL::Int,            NDBCOL::Smallunsigned,  check_compat_lossy,
 
427
   convert_integral< Hint32, Huint16>},
 
428
  {NDBCOL::Int,            NDBCOL::Mediumunsigned, check_compat_lossy,
 
429
   convert_integral< Hint32, Huint24>},
 
430
  {NDBCOL::Bigint,         NDBCOL::Tinyunsigned,   check_compat_lossy,
 
431
   convert_integral< Hint64, Huint8>},
 
432
  {NDBCOL::Bigint,         NDBCOL::Smallunsigned,  check_compat_lossy,
 
433
   convert_integral< Hint64, Huint16>},
 
434
  {NDBCOL::Bigint,         NDBCOL::Mediumunsigned, check_compat_lossy,
 
435
   convert_integral< Hint64, Huint24>},
 
436
  {NDBCOL::Bigint,         NDBCOL::Unsigned,       check_compat_lossy,
 
437
   convert_integral< Hint64, Huint32>},
 
438
  {NDBCOL::Smallunsigned,  NDBCOL::Tinyint,        check_compat_lossy,
 
439
   convert_integral< Huint16, Hint8>},
 
440
  {NDBCOL::Mediumunsigned, NDBCOL::Tinyint,        check_compat_lossy,
 
441
   convert_integral< Huint24, Hint8>},
 
442
  {NDBCOL::Mediumunsigned, NDBCOL::Smallint,       check_compat_lossy,
 
443
   convert_integral< Huint24, Hint16>},
 
444
  {NDBCOL::Unsigned,       NDBCOL::Tinyint,        check_compat_lossy,
 
445
   convert_integral< Huint32, Hint8>},
 
446
  {NDBCOL::Unsigned,       NDBCOL::Smallint,       check_compat_lossy,
 
447
   convert_integral< Huint32, Hint16>},
 
448
  {NDBCOL::Unsigned,       NDBCOL::Mediumint,      check_compat_lossy,
 
449
   convert_integral< Huint32, Hint24>},
 
450
  {NDBCOL::Bigunsigned,    NDBCOL::Tinyint,        check_compat_lossy,
 
451
   convert_integral< Huint64, Hint8>},
 
452
  {NDBCOL::Bigunsigned,    NDBCOL::Smallint,       check_compat_lossy,
 
453
   convert_integral< Huint64, Hint16>},
 
454
  {NDBCOL::Bigunsigned,    NDBCOL::Mediumint,      check_compat_lossy,
 
455
   convert_integral< Huint64, Hint24>},
 
456
  {NDBCOL::Bigunsigned,    NDBCOL::Int,            check_compat_lossy,
 
457
   convert_integral< Huint64, Hint32>},
 
458
 
 
459
  {NDBCOL::Undefined,      NDBCOL::Undefined,      NULL,                  NULL}
 
460
};
 
461
 
 
462
bool
 
463
BackupRestore::init(Uint32 tableChangesMask)
 
464
{
 
465
  release();
 
466
 
 
467
  if (!m_restore && !m_restore_meta && !m_restore_epoch &&
 
468
      !m_rebuild_indexes && !m_disable_indexes)
 
469
    return true;
 
470
 
 
471
  m_tableChangesMask = tableChangesMask;
 
472
  m_cluster_connection = new Ndb_cluster_connection(m_ndb_connectstring,
 
473
                                                    m_ndb_nodeid);
 
474
  if (m_cluster_connection == NULL)
 
475
  {
 
476
    err << "Failed to create cluster connection!!" << endl;
 
477
    return false;
 
478
  }
 
479
  m_cluster_connection->set_name(g_options.c_str());
 
480
  if(m_cluster_connection->connect(12, 5, 1) != 0)
 
481
  {
 
482
    return false;
 
483
  }
 
484
 
 
485
  m_ndb = new Ndb(m_cluster_connection);
 
486
 
 
487
  if (m_ndb == NULL)
 
488
    return false;
 
489
  
 
490
  m_ndb->init(1024);
 
491
  if (m_ndb->waitUntilReady(30) != 0)
 
492
  {
 
493
    err << "Failed to connect to ndb!!" << endl;
 
494
    return false;
 
495
  }
 
496
  info << "Connected to ndb!!" << endl;
 
497
 
 
498
  m_callback = new restore_callback_t[m_parallelism];
 
499
 
 
500
  if (m_callback == 0)
 
501
  {
 
502
    err << "Failed to allocate callback structs" << endl;
 
503
    return false;
 
504
  }
 
505
 
 
506
  m_free_callback= m_callback;
 
507
  for (Uint32 i= 0; i < m_parallelism; i++) {
 
508
    m_callback[i].restore= this;
 
509
    m_callback[i].connection= 0;
 
510
    if (i > 0)
 
511
      m_callback[i-1].next= &(m_callback[i]);
 
512
  }
 
513
  m_callback[m_parallelism-1].next = 0;
 
514
 
 
515
  return true;
 
516
}
 
517
 
 
518
void BackupRestore::release()
 
519
{
 
520
  if (m_ndb)
 
521
  {
 
522
    delete m_ndb;
 
523
    m_ndb= 0;
 
524
  }
 
525
 
 
526
  if (m_callback)
 
527
  {
 
528
    delete [] m_callback;
 
529
    m_callback= 0;
 
530
  }
 
531
 
 
532
  if (m_cluster_connection)
 
533
  {
 
534
    delete m_cluster_connection;
 
535
    m_cluster_connection= 0;
 
536
  }
 
537
}
 
538
 
 
539
BackupRestore::~BackupRestore()
 
540
{
 
541
  release();
 
542
}
 
543
 
 
544
static
 
545
int 
 
546
match_blob(const char * name){
 
547
  int cnt, id1, id2;
 
548
  char buf[256];
 
549
  if((cnt = sscanf(name, "%[^/]/%[^/]/NDB$BLOB_%d_%d", buf, buf, &id1, &id2)) == 4){
 
550
    return id1;
 
551
  }
 
552
  
 
553
  return -1;
 
554
}
 
555
 
 
556
/**
 
557
 * Extracts the database, schema, and table name from an internal table name;
 
558
 * prints an error message and returns false in case of a format violation.
 
559
 */
 
560
static
 
561
bool
 
562
dissect_table_name(const char * qualified_table_name,
 
563
                   BaseString & db_name,
 
564
                   BaseString & schema_name,
 
565
                   BaseString & table_name) {
 
566
  Vector<BaseString> split;
 
567
  BaseString tmp(qualified_table_name);
 
568
  if (tmp.split(split, "/") != 3) {
 
569
    err << "Invalid table name format `" << qualified_table_name
 
570
        << "`" << endl;
 
571
    return false;
 
572
  }
 
573
  db_name = split[0];
 
574
  schema_name = split[1];
 
575
  table_name = split[2];
 
576
  return true;
 
577
}
 
578
 
 
579
/**
 
580
 * Assigns the new name for a database, if and only if to be rewritten.
 
581
 */
 
582
static
 
583
void
 
584
check_rewrite_database(BaseString & db_name) {
 
585
  const char * new_db_name;
 
586
  if (g_rewrite_databases.get(db_name.c_str(), &new_db_name))
 
587
    db_name.assign(new_db_name);
 
588
}
 
589
 
 
590
const NdbDictionary::Table*
 
591
BackupRestore::get_table(const NdbDictionary::Table* tab){
 
592
  if(m_cache.m_old_table == tab)
 
593
    return m_cache.m_new_table;
 
594
  m_cache.m_old_table = tab;
 
595
 
 
596
  int cnt, id1, id2;
 
597
  char db[256], schema[256];
 
598
  if (strcmp(tab->getName(), "SYSTAB_0") == 0 ||
 
599
      strcmp(tab->getName(), "sys/def/SYSTAB_0") == 0) {
 
600
    /*
 
601
      Restore SYSTAB_0 to itself
 
602
    */
 
603
    m_cache.m_new_table = tab;
 
604
  }
 
605
  else if((cnt = sscanf(tab->getName(), "%[^/]/%[^/]/NDB$BLOB_%d_%d", 
 
606
                        db, schema, &id1, &id2)) == 4){
 
607
    m_ndb->setDatabaseName(db);
 
608
    m_ndb->setSchemaName(schema);
 
609
    
 
610
    BaseString::snprintf(db, sizeof(db), "NDB$BLOB_%d_%d", 
 
611
                         m_new_tables[id1]->getTableId(), id2);
 
612
    
 
613
    m_cache.m_new_table = m_ndb->getDictionary()->getTable(db);
 
614
    
 
615
  } else {
 
616
    m_cache.m_new_table = m_new_tables[tab->getTableId()];
 
617
  }
 
618
  assert(m_cache.m_new_table);
 
619
  return m_cache.m_new_table;
 
620
}
 
621
 
 
622
bool
 
623
BackupRestore::finalize_table(const TableS & table){
 
624
  bool ret= true;
 
625
  if (!m_restore && !m_restore_meta)
 
626
    return ret;
 
627
  if (!table.have_auto_inc())
 
628
    return ret;
 
629
 
 
630
  Uint64 max_val= table.get_max_auto_val();
 
631
  do
 
632
  {
 
633
    Uint64 auto_val = ~(Uint64)0;
 
634
    int r= m_ndb->readAutoIncrementValue(get_table(table.m_dictTable), auto_val);
 
635
    if (r == -1 && m_ndb->getNdbError().status == NdbError::TemporaryError)
 
636
    {
 
637
      NdbSleep_MilliSleep(50);
 
638
      continue; // retry
 
639
    }
 
640
    else if (r == -1 && m_ndb->getNdbError().code != 626)
 
641
    {
 
642
      ret= false;
 
643
    }
 
644
    else if ((r == -1 && m_ndb->getNdbError().code == 626) ||
 
645
             max_val+1 > auto_val || auto_val == ~(Uint64)0)
 
646
    {
 
647
      r= m_ndb->setAutoIncrementValue(get_table(table.m_dictTable),
 
648
                                      max_val+1, false);
 
649
      if (r == -1 &&
 
650
            m_ndb->getNdbError().status == NdbError::TemporaryError)
 
651
      {
 
652
        NdbSleep_MilliSleep(50);
 
653
        continue; // retry
 
654
      }
 
655
      ret = (r == 0);
 
656
    }
 
657
    return (ret);
 
658
  } while (1);
 
659
}
 
660
 
 
661
bool
 
662
BackupRestore::rebuild_indexes(const TableS& table)
 
663
{
 
664
  const char *tablename = table.getTableName();
 
665
 
 
666
  const NdbDictionary::Table * tab = get_table(table.m_dictTable);
 
667
  Uint32 id = tab->getObjectId();
 
668
  if (m_index_per_table.size() <= id)
 
669
    return true;
 
670
 
 
671
  BaseString db_name, schema_name, table_name;
 
672
  if (!dissect_table_name(tablename, db_name, schema_name, table_name)) {
 
673
    return false;
 
674
  }
 
675
  check_rewrite_database(db_name);
 
676
 
 
677
  m_ndb->setDatabaseName(db_name.c_str());
 
678
  m_ndb->setSchemaName(schema_name.c_str());
 
679
  NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
 
680
 
 
681
  Vector<NdbDictionary::Index*> & indexes = m_index_per_table[id];
 
682
  for(size_t i = 0; i<indexes.size(); i++)
 
683
  {
 
684
    const NdbDictionary::Index * const idx = indexes[i];
 
685
    const char * const idx_name = idx->getName();
 
686
    const char * const tab_name = idx->getTable();
 
687
    Uint64 start = NdbTick_CurrentMillisecond();
 
688
    info << "Rebuilding index `" << idx_name << "` on table `"
 
689
      << tab_name << "` ..." << flush;
 
690
    if ((dict->getIndex(idx_name, tab_name) == NULL)
 
691
        && (dict->createIndex(* idx, 1) != 0))
 
692
    {
 
693
      info << "FAIL!" << endl;
 
694
      err << "Rebuilding index `" << idx_name << "` on table `"
 
695
        << tab_name <<"` failed: ";
 
696
      err << dict->getNdbError() << endl;
 
697
 
 
698
      return false;
 
699
    }
 
700
    Uint64 stop = NdbTick_CurrentMillisecond();
 
701
    info << "OK (" << ((stop - start)/1000) << "s)" <<endl;
 
702
  }
 
703
 
 
704
  return true;
 
705
}
 
706
 
 
707
#ifdef NOT_USED
 
708
static bool default_nodegroups(NdbDictionary::Table *table)
 
709
{
 
710
  Uint16 *node_groups = (Uint16*)table->getFragmentData();
 
711
  Uint32 no_parts = table->getFragmentDataLen() >> 1;
 
712
  Uint32 i;
 
713
 
 
714
  if (node_groups[0] != 0)
 
715
    return false; 
 
716
  for (i = 1; i < no_parts; i++) 
 
717
  {
 
718
    if (node_groups[i] != NDB_UNDEF_NODEGROUP)
 
719
      return false;
 
720
  }
 
721
  return true;
 
722
}
 
723
#endif
 
724
 
 
725
 
 
726
static Uint32 get_no_fragments(Uint64 max_rows, Uint32 no_nodes)
 
727
{
 
728
  Uint32 i = 0;
 
729
  Uint32 acc_row_size = 27;
 
730
  Uint32 acc_fragment_size = 512*1024*1024;
 
731
  Uint32 no_parts= Uint32((max_rows*acc_row_size)/acc_fragment_size + 1);
 
732
  Uint32 reported_parts = no_nodes; 
 
733
  while (reported_parts < no_parts && ++i < 4 &&
 
734
         (reported_parts + no_parts) < MAX_NDB_PARTITIONS)
 
735
    reported_parts+= no_nodes;
 
736
  if (reported_parts < no_parts)
 
737
  {
 
738
    err << "Table will be restored but will not be able to handle the maximum";
 
739
    err << " amount of rows as requested" << endl;
 
740
  }
 
741
  return reported_parts;
 
742
}
 
743
 
 
744
 
 
745
static void set_default_nodegroups(NdbDictionary::Table *table)
 
746
{
 
747
  Uint32 no_parts = table->getFragmentCount();
 
748
  Uint32 node_group[MAX_NDB_PARTITIONS];
 
749
  Uint32 i;
 
750
 
 
751
  node_group[0] = 0;
 
752
  for (i = 1; i < no_parts; i++)
 
753
  {
 
754
    node_group[i] = NDB_UNDEF_NODEGROUP;
 
755
  }
 
756
  table->setFragmentData(node_group, no_parts);
 
757
}
 
758
 
 
759
Uint32 BackupRestore::map_ng(Uint32 ng)
 
760
{
 
761
  NODE_GROUP_MAP *ng_map = m_nodegroup_map;
 
762
 
 
763
  if (ng == NDB_UNDEF_NODEGROUP ||
 
764
      ng_map[ng].map_array[0] == NDB_UNDEF_NODEGROUP)
 
765
  {
 
766
    return ng;
 
767
  }
 
768
  else
 
769
  {
 
770
    Uint32 new_ng;
 
771
    Uint32 curr_inx = ng_map[ng].curr_index;
 
772
    Uint32 new_curr_inx = curr_inx + 1;
 
773
 
 
774
    assert(ng < MAX_NDB_PARTITIONS);
 
775
    assert(curr_inx < MAX_MAPS_PER_NODE_GROUP);
 
776
    assert(new_curr_inx < MAX_MAPS_PER_NODE_GROUP);
 
777
 
 
778
    if (new_curr_inx >= MAX_MAPS_PER_NODE_GROUP)
 
779
      new_curr_inx = 0;
 
780
    else if (ng_map[ng].map_array[new_curr_inx] == NDB_UNDEF_NODEGROUP)
 
781
      new_curr_inx = 0;
 
782
    new_ng = ng_map[ng].map_array[curr_inx];
 
783
    ng_map[ng].curr_index = new_curr_inx;
 
784
    return new_ng;
 
785
  }
 
786
}
 
787
 
 
788
 
 
789
bool BackupRestore::map_nodegroups(Uint32 *ng_array, Uint32 no_parts)
 
790
{
 
791
  Uint32 i;
 
792
  bool mapped = FALSE;
 
793
  DBUG_ENTER("map_nodegroups");
 
794
 
 
795
  assert(no_parts < MAX_NDB_PARTITIONS);
 
796
  for (i = 0; i < no_parts; i++)
 
797
  {
 
798
    Uint32 ng;
 
799
    ng = map_ng(ng_array[i]);
 
800
    if (ng != ng_array[i])
 
801
      mapped = TRUE;
 
802
    ng_array[i] = ng;
 
803
  }
 
804
  DBUG_RETURN(mapped);
 
805
}
 
806
 
 
807
 
 
808
static void copy_byte(const char **data, char **new_data, uint *len)
 
809
{
 
810
  **new_data = **data;
 
811
  (*data)++;
 
812
  (*new_data)++;
 
813
  (*len)++;
 
814
}
 
815
 
 
816
 
 
817
bool BackupRestore::search_replace(char *search_str, char **new_data,
 
818
                                   const char **data, const char *end_data,
 
819
                                   uint *new_data_len)
 
820
{
 
821
  uint search_str_len = strlen(search_str);
 
822
  uint inx = 0;
 
823
  bool in_delimiters = FALSE;
 
824
  bool escape_char = FALSE;
 
825
  char start_delimiter = 0;
 
826
  DBUG_ENTER("search_replace");
 
827
 
 
828
  do
 
829
  {
 
830
    char c = **data;
 
831
    copy_byte(data, new_data, new_data_len);
 
832
    if (escape_char)
 
833
    {
 
834
      escape_char = FALSE;
 
835
    }
 
836
    else if (in_delimiters)
 
837
    {
 
838
      if (c == start_delimiter)
 
839
        in_delimiters = FALSE;
 
840
    }
 
841
    else if (c == '\'' || c == '\"')
 
842
    {
 
843
      in_delimiters = TRUE;
 
844
      start_delimiter = c;
 
845
    }
 
846
    else if (c == '\\')
 
847
    {
 
848
      escape_char = TRUE;
 
849
    }
 
850
    else if (c == search_str[inx])
 
851
    {
 
852
      inx++;
 
853
      if (inx == search_str_len)
 
854
      {
 
855
        bool found = FALSE;
 
856
        uint number = 0;
 
857
        while (*data != end_data)
 
858
        {
 
859
          if (isdigit(**data))
 
860
          {
 
861
            found = TRUE;
 
862
            number = (10 * number) + (**data);
 
863
            if (number > MAX_NDB_NODES)
 
864
              break;
 
865
          }
 
866
          else if (found)
 
867
          {
 
868
            /*
 
869
               After long and tedious preparations we have actually found
 
870
               a node group identifier to convert. We'll use the mapping
 
871
               table created for node groups and then insert the new number
 
872
               instead of the old number.
 
873
            */
 
874
            uint temp = map_ng(number);
 
875
            int no_digits = 0;
 
876
            char digits[10];
 
877
            while (temp != 0)
 
878
            {
 
879
              digits[no_digits] = temp % 10;
 
880
              no_digits++;
 
881
              temp/=10;
 
882
            }
 
883
            for (no_digits--; no_digits >= 0; no_digits--)
 
884
            {
 
885
              **new_data = digits[no_digits];
 
886
              *new_data_len+=1;
 
887
            }
 
888
            DBUG_RETURN(FALSE); 
 
889
          }
 
890
          else
 
891
            break;
 
892
          (*data)++;
 
893
        }
 
894
        DBUG_RETURN(TRUE);
 
895
      }
 
896
    }
 
897
    else
 
898
      inx = 0;
 
899
  } while (*data < end_data);
 
900
  DBUG_RETURN(FALSE);
 
901
}
 
902
 
 
903
bool BackupRestore::map_in_frm(char *new_data, const char *data,
 
904
                                       uint data_len, uint *new_data_len)
 
905
{
 
906
  const char *end_data= data + data_len;
 
907
  const char *end_part_data;
 
908
  const char *part_data;
 
909
  char *extra_ptr;
 
910
  uint start_key_definition_len = uint2korr(data + 6);
 
911
  uint key_definition_len = uint4korr(data + 47);
 
912
  uint part_info_len;
 
913
  DBUG_ENTER("map_in_frm");
 
914
 
 
915
  if (data_len < 4096) goto error;
 
916
  extra_ptr = (char*)data + start_key_definition_len + key_definition_len;
 
917
  if ((int)data_len < ((extra_ptr - data) + 2)) goto error;
 
918
  extra_ptr = extra_ptr + 2 + uint2korr(extra_ptr);
 
919
  if ((int)data_len < ((extra_ptr - data) + 2)) goto error;
 
920
  extra_ptr = extra_ptr + 2 + uint2korr(extra_ptr);
 
921
  if ((int)data_len < ((extra_ptr - data) + 4)) goto error;
 
922
  part_info_len = uint4korr(extra_ptr);
 
923
  part_data = extra_ptr + 4;
 
924
  if ((int)data_len < ((part_data + part_info_len) - data)) goto error;
 
925
 
 
926
  do
 
927
  {
 
928
    copy_byte(&data, &new_data, new_data_len);
 
929
  } while (data < part_data);
 
930
  end_part_data = part_data + part_info_len;
 
931
  do
 
932
  {
 
933
    if (search_replace((char*)" NODEGROUP = ", &new_data, &data,
 
934
                       end_part_data, new_data_len))
 
935
      goto error;
 
936
  } while (data != end_part_data);
 
937
  do
 
938
  {
 
939
    copy_byte(&data, &new_data, new_data_len);
 
940
  } while (data < end_data);
 
941
  DBUG_RETURN(FALSE);
 
942
error:
 
943
  DBUG_RETURN(TRUE);
 
944
}
 
945
 
 
946
 
 
947
bool BackupRestore::translate_frm(NdbDictionary::Table *table)
 
948
{
 
949
  uchar *pack_data, *data, *new_pack_data;
 
950
  char *new_data;
 
951
  uint new_data_len;
 
952
  size_t data_len, new_pack_len;
 
953
  uint no_parts, extra_growth;
 
954
  DBUG_ENTER("translate_frm");
 
955
 
 
956
  pack_data = (uchar*) table->getFrmData();
 
957
  no_parts = table->getFragmentCount();
 
958
  /*
 
959
    Add max 4 characters per partition to handle worst case
 
960
    of mapping from single digit to 5-digit number.
 
961
    Fairly future-proof, ok up to 99999 node groups.
 
962
  */
 
963
  extra_growth = no_parts * 4;
 
964
  if (unpackfrm(&data, &data_len, pack_data))
 
965
  {
 
966
    DBUG_RETURN(TRUE);
 
967
  }
 
968
  if ((new_data = (char*) malloc(data_len + extra_growth)))
 
969
  {
 
970
    DBUG_RETURN(TRUE);
 
971
  }
 
972
  if (map_in_frm(new_data, (const char*)data, data_len, &new_data_len))
 
973
  {
 
974
    free(new_data);
 
975
    DBUG_RETURN(TRUE);
 
976
  }
 
977
  if (packfrm((uchar*) new_data, new_data_len,
 
978
              &new_pack_data, &new_pack_len))
 
979
  {
 
980
    free(new_data);
 
981
    DBUG_RETURN(TRUE);
 
982
  }
 
983
  table->setFrm(new_pack_data, (Uint32)new_pack_len);
 
984
  DBUG_RETURN(FALSE);
 
985
}
 
986
 
 
987
#include <signaldata/DictTabInfo.hpp>
 
988
 
 
989
bool
 
990
BackupRestore::object(Uint32 type, const void * ptr)
 
991
{
 
992
  if (!m_restore_meta)
 
993
    return true;
 
994
  
 
995
  NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
 
996
  switch(type){
 
997
  case DictTabInfo::Tablespace:
 
998
  {
 
999
    NdbDictionary::Tablespace old(*(NdbDictionary::Tablespace*)ptr);
 
1000
 
 
1001
    Uint32 id = old.getObjectId();
 
1002
 
 
1003
    if (!m_no_restore_disk)
 
1004
    {
 
1005
      NdbDictionary::LogfileGroup * lg = m_logfilegroups[old.getDefaultLogfileGroupId()];
 
1006
      old.setDefaultLogfileGroup(* lg);
 
1007
      info << "Creating tablespace: " << old.getName() << "..." << flush;
 
1008
      int ret = dict->createTablespace(old);
 
1009
      if (ret)
 
1010
      {
 
1011
        NdbError errobj= dict->getNdbError();
 
1012
        info << "FAILED" << endl;
 
1013
        err << "Create tablespace failed: " << old.getName() << ": " << errobj << endl;
 
1014
        return false;
 
1015
      }
 
1016
      info << "done" << endl;
 
1017
    }
 
1018
    
 
1019
    NdbDictionary::Tablespace curr = dict->getTablespace(old.getName());
 
1020
    NdbError errobj = dict->getNdbError();
 
1021
    if ((int) errobj.classification == (int) ndberror_cl_none)
 
1022
    {
 
1023
      NdbDictionary::Tablespace* currptr = new NdbDictionary::Tablespace(curr);
 
1024
      NdbDictionary::Tablespace * null = 0;
 
1025
      m_tablespaces.set(currptr, id, null);
 
1026
      debug << "Retreived tablespace: " << currptr->getName() 
 
1027
            << " oldid: " << id << " newid: " << currptr->getObjectId() 
 
1028
            << " " << (void*)currptr << endl;
 
1029
      m_n_tablespace++;
 
1030
      return true;
 
1031
    }
 
1032
    
 
1033
    err << "Failed to retrieve tablespace \"" << old.getName() << "\": "
 
1034
        << errobj << endl;
 
1035
    
 
1036
    return false;
 
1037
    break;
 
1038
  }
 
1039
  case DictTabInfo::LogfileGroup:
 
1040
  {
 
1041
    NdbDictionary::LogfileGroup old(*(NdbDictionary::LogfileGroup*)ptr);
 
1042
    
 
1043
    Uint32 id = old.getObjectId();
 
1044
    
 
1045
    if (!m_no_restore_disk)
 
1046
    {
 
1047
      info << "Creating logfile group: " << old.getName() << "..." << flush;
 
1048
      int ret = dict->createLogfileGroup(old);
 
1049
      if (ret)
 
1050
      {
 
1051
        NdbError errobj= dict->getNdbError();
 
1052
        info << "FAILED" << endl;
 
1053
        err << "Create logfile group failed: " << old.getName() << ": " << errobj << endl;
 
1054
        return false;
 
1055
      }
 
1056
      info << "done" << endl;
 
1057
    }
 
1058
    
 
1059
    NdbDictionary::LogfileGroup curr = dict->getLogfileGroup(old.getName());
 
1060
    NdbError errobj = dict->getNdbError();
 
1061
    if ((int) errobj.classification == (int) ndberror_cl_none)
 
1062
    {
 
1063
      NdbDictionary::LogfileGroup* currptr = 
 
1064
        new NdbDictionary::LogfileGroup(curr);
 
1065
      NdbDictionary::LogfileGroup * null = 0;
 
1066
      m_logfilegroups.set(currptr, id, null);
 
1067
      debug << "Retreived logfile group: " << currptr->getName() 
 
1068
            << " oldid: " << id << " newid: " << currptr->getObjectId() 
 
1069
            << " " << (void*)currptr << endl;
 
1070
      m_n_logfilegroup++;
 
1071
      return true;
 
1072
    }
 
1073
    
 
1074
    err << "Failed to retrieve logfile group \"" << old.getName() << "\": "
 
1075
        << errobj << endl;
 
1076
    
 
1077
    return false;
 
1078
    break;
 
1079
  }
 
1080
  case DictTabInfo::Datafile:
 
1081
  {
 
1082
    if (!m_no_restore_disk)
 
1083
    {
 
1084
      NdbDictionary::Datafile old(*(NdbDictionary::Datafile*)ptr);
 
1085
      NdbDictionary::ObjectId objid;
 
1086
      old.getTablespaceId(&objid);
 
1087
      NdbDictionary::Tablespace * ts = m_tablespaces[objid.getObjectId()];
 
1088
      debug << "Connecting datafile " << old.getPath() 
 
1089
            << " to tablespace: oldid: " << objid.getObjectId()
 
1090
            << " newid: " << ts->getObjectId() << endl;
 
1091
      old.setTablespace(* ts);
 
1092
      info << "Creating datafile \"" << old.getPath() << "\"..." << flush;
 
1093
      if (dict->createDatafile(old))
 
1094
      {
 
1095
        NdbError errobj= dict->getNdbError();
 
1096
        info << "FAILED" << endl;
 
1097
        err << "Create datafile failed: " << old.getPath() << ": " << errobj << endl;
 
1098
        return false;
 
1099
      }
 
1100
      info << "done" << endl;
 
1101
      m_n_datafile++;
 
1102
    }
 
1103
    return true;
 
1104
    break;
 
1105
  }
 
1106
  case DictTabInfo::Undofile:
 
1107
  {
 
1108
    if (!m_no_restore_disk)
 
1109
    {
 
1110
      NdbDictionary::Undofile old(*(NdbDictionary::Undofile*)ptr);
 
1111
      NdbDictionary::ObjectId objid;
 
1112
      old.getLogfileGroupId(&objid);
 
1113
      NdbDictionary::LogfileGroup * lg = m_logfilegroups[objid.getObjectId()];
 
1114
      debug << "Connecting undofile " << old.getPath() 
 
1115
            << " to logfile group: oldid: " << objid.getObjectId()
 
1116
            << " newid: " << lg->getObjectId() 
 
1117
            << " " << (void*)lg << endl;
 
1118
      old.setLogfileGroup(* lg);
 
1119
      info << "Creating undofile \"" << old.getPath() << "\"..." << flush;
 
1120
      if (dict->createUndofile(old))
 
1121
      {
 
1122
        NdbError errobj= dict->getNdbError();
 
1123
        info << "FAILED" << endl;
 
1124
        err << "Create undofile failed: " << old.getPath() << ": " << errobj << endl;
 
1125
        return false;
 
1126
      }
 
1127
      info << "done" << endl;
 
1128
      m_n_undofile++;
 
1129
    }
 
1130
    return true;
 
1131
    break;
 
1132
  }
 
1133
  case DictTabInfo::HashMap:
 
1134
  {
 
1135
    NdbDictionary::HashMap old(*(NdbDictionary::HashMap*)ptr);
 
1136
 
 
1137
    Uint32 id = old.getObjectId();
 
1138
 
 
1139
    if (m_restore_meta)
 
1140
    {
 
1141
      int ret = dict->createHashMap(old);
 
1142
      if (ret == 0)
 
1143
      {
 
1144
        info << "Created hashmap: " << old.getName() << endl;
 
1145
      }
 
1146
      else
 
1147
      {
 
1148
        NdbError errobj = dict->getNdbError();
 
1149
        // We ignore schema already exists, this is fine
 
1150
        if (errobj.code != 721)
 
1151
        {
 
1152
          err << "Could not create hashmap \"" << old.getName() << "\": "
 
1153
              << errobj << endl;
 
1154
          return false;
 
1155
        }
 
1156
      }
 
1157
    }
 
1158
 
 
1159
    NdbDictionary::HashMap curr;
 
1160
    if (dict->getHashMap(curr, old.getName()) == 0)
 
1161
    {
 
1162
      NdbDictionary::HashMap* currptr =
 
1163
        new NdbDictionary::HashMap(curr);
 
1164
      NdbDictionary::HashMap * null = 0;
 
1165
      m_hashmaps.set(currptr, id, null);
 
1166
      debug << "Retreived hashmap: " << currptr->getName()
 
1167
            << " oldid: " << id << " newid: " << currptr->getObjectId()
 
1168
            << " " << (void*)currptr << endl;
 
1169
      return true;
 
1170
    }
 
1171
 
 
1172
    NdbError errobj = dict->getNdbError();
 
1173
    err << "Failed to retrieve hashmap \"" << old.getName() << "\": "
 
1174
        << errobj << endl;
 
1175
 
 
1176
    return false;
 
1177
  }
 
1178
  default:
 
1179
  {
 
1180
    err << "Unknown object type: " << type << endl;
 
1181
    break;
 
1182
  }
 
1183
  }
 
1184
  return true;
 
1185
}
 
1186
 
 
1187
bool
 
1188
BackupRestore::has_temp_error(){
 
1189
  return m_temp_error;
 
1190
}
 
1191
 
 
1192
bool
 
1193
BackupRestore::update_apply_status(const RestoreMetaData &metaData)
 
1194
{
 
1195
  if (!m_restore_epoch)
 
1196
    return true;
 
1197
 
 
1198
  bool result= false;
 
1199
  unsigned apply_table_format= 0;
 
1200
 
 
1201
  m_ndb->setDatabaseName(NDB_REP_DB);
 
1202
  m_ndb->setSchemaName("def");
 
1203
 
 
1204
  NdbDictionary::Dictionary *dict= m_ndb->getDictionary();
 
1205
  const NdbDictionary::Table *ndbtab= dict->getTable(NDB_APPLY_TABLE);
 
1206
  if (!ndbtab)
 
1207
  {
 
1208
    err << NDB_APPLY_TABLE << ": "
 
1209
        << dict->getNdbError() << endl;
 
1210
    return false;
 
1211
  }
 
1212
  if (ndbtab->getColumn(0)->getType() == NdbDictionary::Column::Unsigned &&
 
1213
      ndbtab->getColumn(1)->getType() == NdbDictionary::Column::Bigunsigned)
 
1214
  {
 
1215
    if (ndbtab->getNoOfColumns() == 2)
 
1216
    {
 
1217
      apply_table_format= 1;
 
1218
    }
 
1219
    else if
 
1220
      (ndbtab->getColumn(2)->getType() == NdbDictionary::Column::Varchar &&
 
1221
       ndbtab->getColumn(3)->getType() == NdbDictionary::Column::Bigunsigned &&
 
1222
       ndbtab->getColumn(4)->getType() == NdbDictionary::Column::Bigunsigned)
 
1223
    {
 
1224
      apply_table_format= 2;
 
1225
    }
 
1226
  }
 
1227
  if (apply_table_format == 0)
 
1228
  {
 
1229
    err << NDB_APPLY_TABLE << " has wrong format\n";
 
1230
    return false;
 
1231
  }
 
1232
 
 
1233
  Uint32 server_id= 0;
 
1234
  Uint64 epoch= Uint64(metaData.getStopGCP());
 
1235
  Uint32 version= metaData.getNdbVersion();
 
1236
 
 
1237
  /**
 
1238
   * Bug#XXX, stopGCP is not really stop GCP, but stopGCP - 1
 
1239
   */
 
1240
  epoch += 1;
 
1241
 
 
1242
  if (version >= NDBD_MICRO_GCP_63 ||
 
1243
      (version >= NDBD_MICRO_GCP_62 && getMinor(version) == 2))
 
1244
  {
 
1245
    epoch<<= 32; // Only gci_hi is saved...
 
1246
 
 
1247
    /**
 
1248
     * Backup contains all epochs with those top bits,
 
1249
     * so we indicate that with max setting
 
1250
     */
 
1251
    epoch += (Uint64(1) << 32) - 1;
 
1252
  }
 
1253
 
 
1254
  Uint64 zero= 0;
 
1255
  char empty_string[1];
 
1256
  empty_string[0]= 0;
 
1257
  NdbTransaction * trans= m_ndb->startTransaction();
 
1258
  if (!trans)
 
1259
  {
 
1260
    err << NDB_APPLY_TABLE << ": "
 
1261
        << m_ndb->getNdbError() << endl;
 
1262
    return false;
 
1263
  }
 
1264
  NdbOperation * op= trans->getNdbOperation(ndbtab);
 
1265
  if (!op)
 
1266
  {
 
1267
    err << NDB_APPLY_TABLE << ": "
 
1268
        << trans->getNdbError() << endl;
 
1269
    goto err;
 
1270
  }
 
1271
  if (op->writeTuple() ||
 
1272
      op->equal(0u, (const char *)&server_id, sizeof(server_id)) ||
 
1273
      op->setValue(1u, (const char *)&epoch, sizeof(epoch)))
 
1274
  {
 
1275
    err << NDB_APPLY_TABLE << ": "
 
1276
        << op->getNdbError() << endl;
 
1277
    goto err;
 
1278
  }
 
1279
  if ((apply_table_format == 2) &&
 
1280
      (op->setValue(2u, (const char *)&empty_string, 1) ||
 
1281
       op->setValue(3u, (const char *)&zero, sizeof(zero)) ||
 
1282
       op->setValue(4u, (const char *)&zero, sizeof(zero))))
 
1283
  {
 
1284
    err << NDB_APPLY_TABLE << ": "
 
1285
        << op->getNdbError() << endl;
 
1286
    goto err;
 
1287
  }
 
1288
  if (trans->execute(NdbTransaction::Commit))
 
1289
  {
 
1290
    err << NDB_APPLY_TABLE << ": "
 
1291
        << trans->getNdbError() << endl;
 
1292
    goto err;
 
1293
  }
 
1294
  result= true;
 
1295
err:
 
1296
  m_ndb->closeTransaction(trans);
 
1297
  return result;
 
1298
}
 
1299
 
 
1300
bool
 
1301
BackupRestore::report_started(unsigned backup_id, unsigned node_id)
 
1302
{
 
1303
  if (m_ndb)
 
1304
  {
 
1305
    Uint32 data[3];
 
1306
    data[0]= NDB_LE_RestoreStarted;
 
1307
    data[1]= backup_id;
 
1308
    data[2]= node_id;
 
1309
    Ndb_internal::send_event_report(false /* has lock */, m_ndb, data, 3);
 
1310
  }
 
1311
  return true;
 
1312
}
 
1313
 
 
1314
bool
 
1315
BackupRestore::report_meta_data(unsigned backup_id, unsigned node_id)
 
1316
{
 
1317
  if (m_ndb)
 
1318
  {
 
1319
    Uint32 data[8];
 
1320
    data[0]= NDB_LE_RestoreMetaData;
 
1321
    data[1]= backup_id;
 
1322
    data[2]= node_id;
 
1323
    data[3]= m_n_tables;
 
1324
    data[4]= m_n_tablespace;
 
1325
    data[5]= m_n_logfilegroup;
 
1326
    data[6]= m_n_datafile;
 
1327
    data[7]= m_n_undofile;
 
1328
    Ndb_internal::send_event_report(false /* has lock */, m_ndb, data, 8);
 
1329
  }
 
1330
  return true;
 
1331
}
 
1332
bool
 
1333
BackupRestore::report_data(unsigned backup_id, unsigned node_id)
 
1334
{
 
1335
  if (m_ndb)
 
1336
  {
 
1337
    Uint32 data[7];
 
1338
    data[0]= NDB_LE_RestoreData;
 
1339
    data[1]= backup_id;
 
1340
    data[2]= node_id;
 
1341
    data[3]= m_dataCount & 0xFFFFFFFF;
 
1342
    data[4]= 0;
 
1343
    data[5]= (Uint32)(m_dataBytes & 0xFFFFFFFF);
 
1344
    data[6]= (Uint32)((m_dataBytes >> 32) & 0xFFFFFFFF);
 
1345
    Ndb_internal::send_event_report(false /* has lock */, m_ndb, data, 7);
 
1346
  }
 
1347
  return true;
 
1348
}
 
1349
 
 
1350
bool
 
1351
BackupRestore::report_log(unsigned backup_id, unsigned node_id)
 
1352
{
 
1353
  if (m_ndb)
 
1354
  {
 
1355
    Uint32 data[7];
 
1356
    data[0]= NDB_LE_RestoreLog;
 
1357
    data[1]= backup_id;
 
1358
    data[2]= node_id;
 
1359
    data[3]= m_logCount & 0xFFFFFFFF;
 
1360
    data[4]= 0;
 
1361
    data[5]= (Uint32)(m_logBytes & 0xFFFFFFFF);
 
1362
    data[6]= (Uint32)((m_logBytes >> 32) & 0xFFFFFFFF);
 
1363
    Ndb_internal::send_event_report(false /* has lock */, m_ndb, data, 7);
 
1364
  }
 
1365
  return true;
 
1366
}
 
1367
 
 
1368
bool
 
1369
BackupRestore::report_completed(unsigned backup_id, unsigned node_id)
 
1370
{
 
1371
  if (m_ndb)
 
1372
  {
 
1373
    Uint32 data[3];
 
1374
    data[0]= NDB_LE_RestoreCompleted;
 
1375
    data[1]= backup_id;
 
1376
    data[2]= node_id;
 
1377
    Ndb_internal::send_event_report(false /* has lock */, m_ndb, data, 3);
 
1378
  }
 
1379
  return true;
 
1380
}
 
1381
 
 
1382
bool
 
1383
BackupRestore::column_compatible_check(const char* tableName, 
 
1384
                                       const NDBCOL* backupCol, 
 
1385
                                       const NDBCOL* dbCol)
 
1386
{
 
1387
  if (backupCol->equal(*dbCol))
 
1388
    return true;
 
1389
 
 
1390
  /* Something is different between the columns, but some differences don't
 
1391
   * matter.
 
1392
   * Investigate which parts are different, and inform user
 
1393
   */
 
1394
  bool similarEnough = true;
 
1395
 
 
1396
  /* We check similar things to NdbColumnImpl::equal() here */
 
1397
  if (strcmp(backupCol->getName(), dbCol->getName()) != 0)
 
1398
  {
 
1399
    info << "Column " << tableName << "." << backupCol->getName()
 
1400
         << " has different name in DB (" << dbCol->getName() << ")"
 
1401
         << endl;
 
1402
    similarEnough = false;
 
1403
  }
 
1404
  
 
1405
  if (backupCol->getType() != dbCol->getType())
 
1406
  {
 
1407
    info << "Column " << tableName << "." << backupCol->getName()
 
1408
         << (" has different type in DB; promotion or lossy type conversion"
 
1409
             " (demotion, signed/unsigned) may be required.") << endl;
 
1410
    similarEnough = false;
 
1411
  }
 
1412
 
 
1413
  if (backupCol->getPrimaryKey() != dbCol->getPrimaryKey())
 
1414
  {
 
1415
    info << "Column " << tableName << "." << backupCol->getName()
 
1416
         << (dbCol->getPrimaryKey()?" is":" is not")
 
1417
         << " a primary key in the DB." << endl;
 
1418
    similarEnough = false;
 
1419
  }
 
1420
  else
 
1421
  {
 
1422
    if (backupCol->getPrimaryKey())
 
1423
    {
 
1424
      if (backupCol->getDistributionKey() != dbCol->getDistributionKey())
 
1425
      {
 
1426
        info << "Column " << tableName << "." << backupCol->getName()
 
1427
             << (dbCol->getDistributionKey()?" is":" is not")
 
1428
             << " a distribution key in the DB." << endl;
 
1429
        /* Not a problem for restore though */
 
1430
      }
 
1431
    }
 
1432
  }
 
1433
 
 
1434
  if (backupCol->getNullable() != dbCol->getNullable())
 
1435
  {
 
1436
    info << "Column " << tableName << "." << backupCol->getName()
 
1437
         << (dbCol->getNullable()?" is":" is not")
 
1438
         << " nullable in the DB." << endl;
 
1439
    similarEnough = false;
 
1440
  }
 
1441
 
 
1442
  if (backupCol->getPrecision() != dbCol->getPrecision())
 
1443
  {
 
1444
    info << "Column " << tableName << "." << backupCol->getName()
 
1445
         << " precision is different in the DB" << endl;
 
1446
    similarEnough = false;
 
1447
  }
 
1448
 
 
1449
  if (backupCol->getScale() != dbCol->getScale())
 
1450
  {
 
1451
    info <<  "Column " << tableName << "." << backupCol->getName()
 
1452
         << " scale is different in the DB" << endl;
 
1453
    similarEnough = false;
 
1454
  }
 
1455
 
 
1456
  if (backupCol->getLength() != dbCol->getLength())
 
1457
  {
 
1458
    info <<  "Column " << tableName << "." << backupCol->getName()
 
1459
         << " length is different in the DB" << endl;
 
1460
    similarEnough = false;
 
1461
  }
 
1462
 
 
1463
  if (backupCol->getCharset() != dbCol->getCharset())
 
1464
  {
 
1465
    info <<  "Column " << tableName << "." << backupCol->getName()
 
1466
         << " charset is different in the DB" << endl;
 
1467
    similarEnough = false;
 
1468
  }
 
1469
  
 
1470
  if (backupCol->getAutoIncrement() != dbCol->getAutoIncrement())
 
1471
  {
 
1472
    info << "Column " << tableName << "." << backupCol->getName()
 
1473
         << (dbCol->getAutoIncrement()?" is":" is not")
 
1474
         << " AutoIncrementing in the DB" << endl;
 
1475
    /* TODO : Can this be ignored? */
 
1476
    similarEnough = false;
 
1477
  }
 
1478
  
 
1479
  {
 
1480
    unsigned int backupDefaultLen, dbDefaultLen;
 
1481
    const void *backupDefaultPtr, *dbDefaultPtr;
 
1482
    backupDefaultPtr = backupCol->getDefaultValue(&backupDefaultLen);
 
1483
    dbDefaultPtr = dbCol->getDefaultValue(&dbDefaultLen);
 
1484
    
 
1485
    if ((backupDefaultLen != dbDefaultLen) ||
 
1486
        (memcmp(backupDefaultPtr, dbDefaultPtr, backupDefaultLen) != 0))
 
1487
    {
 
1488
      info << "Column " << tableName << "." << backupCol->getName()
 
1489
           << " Default value is different in the DB" << endl;
 
1490
      /* This doesn't matter */
 
1491
    }
 
1492
  }
 
1493
 
 
1494
  if (backupCol->getArrayType() != dbCol->getArrayType())
 
1495
  {
 
1496
    info << "Column " << tableName << "." << backupCol->getName()
 
1497
         << " ArrayType is different in the DB" << endl;
 
1498
    similarEnough = false;
 
1499
  }
 
1500
 
 
1501
  if (backupCol->getStorageType() != dbCol->getStorageType())
 
1502
  {
 
1503
    info << "Column " << tableName << "." << backupCol->getName()
 
1504
         << " Storagetype is different in the DB" << endl;
 
1505
    /* This doesn't matter */
 
1506
  }
 
1507
 
 
1508
  if (backupCol->getBlobVersion() != dbCol->getBlobVersion())
 
1509
  {
 
1510
    info << "Column " << tableName << "." << backupCol->getName()
 
1511
         << " Blob version is different in the DB" << endl;
 
1512
    similarEnough = false;
 
1513
  }
 
1514
 
 
1515
  if (backupCol->getDynamic() != dbCol->getDynamic())
 
1516
  {
 
1517
    info << "Column " << tableName << "." << backupCol->getName()
 
1518
         << (dbCol->getDynamic()?" is":" is not")
 
1519
         << " Dynamic in the DB" << endl;
 
1520
    /* This doesn't matter */
 
1521
  }
 
1522
 
 
1523
  if (similarEnough)
 
1524
    info << "  Difference(s) will be ignored during restore." << endl;
 
1525
  else
 
1526
    info << "  Difference(s) cannot be ignored.  Cannot restore this column as is." << endl;
 
1527
 
 
1528
  return similarEnough;
 
1529
}
 
1530
 
 
1531
bool
 
1532
BackupRestore::table_compatible_check(const TableS & tableS)
 
1533
{
 
1534
  if (!m_restore)
 
1535
    return true;
 
1536
 
 
1537
  const char *tablename = tableS.getTableName();
 
1538
 
 
1539
  if(tableS.m_dictTable == NULL){
 
1540
    ndbout<<"Table %s has no m_dictTable " << tablename << endl;
 
1541
    return false;
 
1542
  }
 
1543
  /**
 
1544
   * Ignore blob tables
 
1545
   */
 
1546
  if(match_blob(tablename) >= 0)
 
1547
    return true;
 
1548
 
 
1549
  const NdbTableImpl & tmptab = NdbTableImpl::getImpl(* tableS.m_dictTable);
 
1550
  if ((int) tmptab.m_indexType != (int) NdbDictionary::Index::Undefined){
 
1551
    return true;
 
1552
  }
 
1553
 
 
1554
  BaseString db_name, schema_name, table_name;
 
1555
  if (!dissect_table_name(tablename, db_name, schema_name, table_name)) {
 
1556
    return false;
 
1557
  }
 
1558
  check_rewrite_database(db_name);
 
1559
 
 
1560
  m_ndb->setDatabaseName(db_name.c_str());
 
1561
  m_ndb->setSchemaName(schema_name.c_str());
 
1562
 
 
1563
  NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
 
1564
  const NdbDictionary::Table* tab = dict->getTable(table_name.c_str());
 
1565
  if(tab == 0){
 
1566
    err << "Unable to find table: " << table_name << endl;
 
1567
    return false;
 
1568
  }
 
1569
 
 
1570
  /**
 
1571
   * remap column(s) based on column-names
 
1572
   */
 
1573
  for (int i = 0; i<tableS.m_dictTable->getNoOfColumns(); i++)
 
1574
  {
 
1575
    AttributeDesc * attr_desc = tableS.getAttributeDesc(i);
 
1576
    const NDBCOL * col_in_backup = tableS.m_dictTable->getColumn(i);
 
1577
    const NDBCOL * col_in_kernel = tab->getColumn(col_in_backup->getName());
 
1578
 
 
1579
    if (col_in_kernel == 0)
 
1580
    {
 
1581
      if ((m_tableChangesMask & TCM_EXCLUDE_MISSING_COLUMNS) == 0)
 
1582
      {
 
1583
        ndbout << "Missing column("
 
1584
               << tableS.m_dictTable->getName() << "."
 
1585
               << col_in_backup->getName()
 
1586
               << ") in DB and exclude-missing-columns not specified" << endl;
 
1587
        return false;
 
1588
      }
 
1589
 
 
1590
      info << "Column in backup ("
 
1591
           << tableS.m_dictTable->getName() << "."
 
1592
           << col_in_backup->getName()
 
1593
           << ") missing in DB.  Excluding column from restore." << endl;
 
1594
 
 
1595
      attr_desc->m_exclude = true;
 
1596
    }
 
1597
    else
 
1598
    {
 
1599
      attr_desc->attrId = col_in_kernel->getColumnNo();
 
1600
    }
 
1601
  }
 
1602
 
 
1603
  for (int i = 0; i<tab->getNoOfColumns(); i++)
 
1604
  {
 
1605
    const NDBCOL * col_in_kernel = tab->getColumn(i);
 
1606
    const NDBCOL * col_in_backup =
 
1607
      tableS.m_dictTable->getColumn(col_in_kernel->getName());
 
1608
 
 
1609
    if (col_in_backup == 0)
 
1610
    {
 
1611
      if ((m_tableChangesMask & TCM_EXCLUDE_MISSING_COLUMNS) == 0)
 
1612
      {
 
1613
        ndbout << "Missing column("
 
1614
               << tableS.m_dictTable->getName() << "."
 
1615
               << col_in_kernel->getName()
 
1616
               << ") in backup and exclude-missing-columns not specified"
 
1617
               << endl;
 
1618
        return false;
 
1619
      }
 
1620
 
 
1621
      /**
 
1622
       * only nullable or defaulted non primary key columns can be missing from backup
 
1623
       *
 
1624
       */
 
1625
      if (col_in_kernel->getPrimaryKey() ||
 
1626
          ((col_in_kernel->getNullable() == false) &&
 
1627
           (col_in_kernel->getDefaultValue() == NULL)))
 
1628
      {
 
1629
        ndbout << "Missing column("
 
1630
               << tableS.m_dictTable->getName() << "."
 
1631
               << col_in_kernel->getName()
 
1632
               << ") in backup is primary key or not nullable or defaulted in DB"
 
1633
               << endl;
 
1634
        return false;
 
1635
      }
 
1636
 
 
1637
      info << "Column in DB ("
 
1638
           << tableS.m_dictTable->getName() << "."
 
1639
           << col_in_kernel->getName()
 
1640
           << ") missing in Backup.  Will be set to "
 
1641
           << ((col_in_kernel->getDefaultValue() == NULL)?"Null":"Default value")
 
1642
           << "." << endl;
 
1643
    }
 
1644
  }
 
1645
 
 
1646
  AttrCheckCompatFunc attrCheckCompatFunc = NULL;
 
1647
  for(int i = 0; i<tableS.m_dictTable->getNoOfColumns(); i++)
 
1648
  {
 
1649
    AttributeDesc * attr_desc = tableS.getAttributeDesc(i);
 
1650
    if (attr_desc->m_exclude)
 
1651
      continue;
 
1652
 
 
1653
    const NDBCOL * col_in_kernel = tab->getColumn(attr_desc->attrId);
 
1654
    const NDBCOL * col_in_backup = tableS.m_dictTable->getColumn(i);
 
1655
 
 
1656
    if(column_compatible_check(tablename,
 
1657
                               col_in_backup, 
 
1658
                               col_in_kernel))
 
1659
    {
 
1660
      continue;
 
1661
    }
 
1662
 
 
1663
    NDBCOL::Type type_in_backup = col_in_backup->getType();
 
1664
    NDBCOL::Type type_in_kernel = col_in_kernel->getType();
 
1665
    attrCheckCompatFunc = get_attr_check_compatability(type_in_backup,
 
1666
                                                       type_in_kernel);
 
1667
    AttrConvType compat
 
1668
      = (attrCheckCompatFunc == NULL ? ACT_UNSUPPORTED
 
1669
         : attrCheckCompatFunc(*col_in_backup, *col_in_kernel));
 
1670
    switch (compat) {
 
1671
    case ACT_UNSUPPORTED:
 
1672
      {
 
1673
        err << "Table: "<< tablename
 
1674
            << " column: " << col_in_backup->getName()
 
1675
            << " incompatible with kernel's definition" << endl;
 
1676
        return false;
 
1677
      }
 
1678
    case ACT_PRESERVING:
 
1679
      if ((m_tableChangesMask & TCM_ATTRIBUTE_PROMOTION) == 0)
 
1680
      {
 
1681
        err << "Table: "<< tablename
 
1682
            << " column: " << col_in_backup->getName()
 
1683
            << " promotable to kernel's definition but option"
 
1684
            << " promote-attributes not specified" << endl;
 
1685
        return false;
 
1686
      }
 
1687
      break;
 
1688
    case ACT_LOSSY:
 
1689
      if ((m_tableChangesMask & TCM_ATTRIBUTE_DEMOTION) == 0)
 
1690
      {
 
1691
        err << "Table: "<< tablename
 
1692
            << " column: " << col_in_backup->getName()
 
1693
            << " convertable to kernel's definition but option"
 
1694
            << " lossy-conversions not specified" << endl;
 
1695
        return false;
 
1696
      }
 
1697
      break;
 
1698
    default:
 
1699
      err << "internal error: illegal value of compat = " << compat << endl;
 
1700
      assert(false);
 
1701
      return false;
 
1702
    };
 
1703
 
 
1704
    attr_desc->convertFunc = get_convert_func(type_in_backup,
 
1705
                                              type_in_kernel);
 
1706
    Uint32 m_attrSize = NdbColumnImpl::getImpl(*col_in_kernel).m_attrSize;
 
1707
    Uint32 m_arraySize = NdbColumnImpl::getImpl(*col_in_kernel).m_arraySize;
 
1708
 
 
1709
    // use a char_n_padding_struct to pass length information to convert()
 
1710
    if (type_in_backup == NDBCOL::Char ||
 
1711
        type_in_backup == NDBCOL::Binary ||
 
1712
        type_in_backup == NDBCOL::Bit ||
 
1713
        type_in_backup == NDBCOL::Varchar ||
 
1714
        type_in_backup == NDBCOL::Longvarchar ||
 
1715
        type_in_backup == NDBCOL::Varbinary ||
 
1716
        type_in_backup == NDBCOL::Longvarbinary)
 
1717
    {
 
1718
      unsigned int size = sizeof(struct char_n_padding_struct) +
 
1719
        m_attrSize * m_arraySize;
 
1720
      struct char_n_padding_struct *s = (struct char_n_padding_struct *)
 
1721
        malloc(size +2);
 
1722
      if (!s)
 
1723
      {
 
1724
        err << "No more memory available!" << endl;
 
1725
        exitHandler();
 
1726
      }
 
1727
      s->n_old = (attr_desc->size * attr_desc->arraySize) / 8;
 
1728
      s->n_new = m_attrSize * m_arraySize;
 
1729
      memset(s->new_row, 0 , m_attrSize * m_arraySize + 2);
 
1730
      attr_desc->parameter = s;
 
1731
    }
 
1732
    else
 
1733
    {
 
1734
      unsigned int size = m_attrSize * m_arraySize;
 
1735
      attr_desc->parameter = malloc(size + 2);
 
1736
      if (!attr_desc->parameter)
 
1737
      {
 
1738
        err << "No more memory available!" << endl;
 
1739
        exitHandler();
 
1740
      }
 
1741
      memset(attr_desc->parameter, 0, size + 2);
 
1742
    }
 
1743
 
 
1744
    info << "Data for column "
 
1745
         << tablename << "."
 
1746
         << col_in_backup->getName()
 
1747
         << " will be converted from Backup type into DB type." << endl;
 
1748
  }
 
1749
 
 
1750
  return true;  
 
1751
}
 
1752
 
 
1753
bool
 
1754
BackupRestore::createSystable(const TableS & tables){
 
1755
  if (!m_restore && !m_restore_meta && !m_restore_epoch)
 
1756
    return true;
 
1757
  const char *tablename = tables.getTableName();
 
1758
 
 
1759
  if( strcmp(tablename, NDB_REP_DB "/def/" NDB_APPLY_TABLE) != 0 &&
 
1760
      strcmp(tablename, NDB_REP_DB "/def/" NDB_SCHEMA_TABLE) != 0 )
 
1761
  {
 
1762
    return true;
 
1763
  }
 
1764
 
 
1765
  BaseString db_name, schema_name, table_name;
 
1766
  if (!dissect_table_name(tablename, db_name, schema_name, table_name)) {
 
1767
    return false;
 
1768
  }
 
1769
  // do not rewrite database for system tables:
 
1770
  // check_rewrite_database(db_name);
 
1771
 
 
1772
  m_ndb->setDatabaseName(db_name.c_str());
 
1773
  m_ndb->setSchemaName(schema_name.c_str());
 
1774
 
 
1775
  NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
 
1776
  if( dict->getTable(table_name.c_str()) != NULL ){
 
1777
    return true;
 
1778
  }
 
1779
  return table(tables);
 
1780
}
 
1781
 
 
1782
bool
 
1783
BackupRestore::table(const TableS & table){
 
1784
  if (!m_restore && !m_restore_meta && !m_rebuild_indexes && !m_disable_indexes)
 
1785
    return true;
 
1786
 
 
1787
  const char * name = table.getTableName();
 
1788
 
 
1789
  /**
 
1790
   * Ignore blob tables
 
1791
   */
 
1792
  if(match_blob(name) >= 0)
 
1793
    return true;
 
1794
  
 
1795
  const NdbTableImpl & tmptab = NdbTableImpl::getImpl(* table.m_dictTable);
 
1796
  if ((int) tmptab.m_indexType != (int) NdbDictionary::Index::Undefined){
 
1797
    m_indexes.push_back(table.m_dictTable);
 
1798
    return true;
 
1799
  }
 
1800
  
 
1801
  BaseString db_name, schema_name, table_name;
 
1802
  if (!dissect_table_name(name, db_name, schema_name, table_name)) {
 
1803
    return false;
 
1804
  }
 
1805
  check_rewrite_database(db_name);
 
1806
 
 
1807
  m_ndb->setDatabaseName(db_name.c_str());
 
1808
  m_ndb->setSchemaName(schema_name.c_str());
 
1809
  
 
1810
  NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
 
1811
  if(m_restore_meta)
 
1812
  {
 
1813
    NdbDictionary::Table copy(*table.m_dictTable);
 
1814
 
 
1815
    copy.setName(table_name.c_str());
 
1816
    Uint32 id;
 
1817
    if (copy.getTablespace(&id))
 
1818
    {
 
1819
      debug << "Connecting " << name << " to tablespace oldid: " << id << flush;
 
1820
      NdbDictionary::Tablespace* ts = m_tablespaces[id];
 
1821
      debug << " newid: " << ts->getObjectId() << endl;
 
1822
      copy.setTablespace(* ts);
 
1823
    }
 
1824
 
 
1825
    if (copy.getFragmentType() == NdbDictionary::Object::HashMapPartition)
 
1826
    {
 
1827
      Uint32 id;
 
1828
      if (copy.getHashMap(&id))
 
1829
      {
 
1830
        NdbDictionary::HashMap * hm = m_hashmaps[id];
 
1831
        copy.setHashMap(* hm);
 
1832
      }
 
1833
    }
 
1834
    else if (copy.getDefaultNoPartitionsFlag())
 
1835
    {
 
1836
      /*
 
1837
        Table was defined with default number of partitions. We can restore
 
1838
        it with whatever is the default in this cluster.
 
1839
        We use the max_rows parameter in calculating the default number.
 
1840
      */
 
1841
      Uint32 no_nodes = m_cluster_connection->no_db_nodes();
 
1842
      copy.setFragmentCount(get_no_fragments(copy.getMaxRows(),
 
1843
                            no_nodes));
 
1844
      set_default_nodegroups(&copy);
 
1845
    }
 
1846
    else
 
1847
    {
 
1848
      /*
 
1849
        Table was defined with specific number of partitions. It should be
 
1850
        restored with the same number of partitions. It will either be
 
1851
        restored in the same node groups as when backup was taken or by
 
1852
        using a node group map supplied to the ndb_restore program.
 
1853
      */
 
1854
      Vector<Uint32> new_array;
 
1855
      Uint16 no_parts = copy.getFragmentCount();
 
1856
      new_array.assign(copy.getFragmentData(), no_parts);
 
1857
      if (map_nodegroups(new_array.getBase(), no_parts))
 
1858
      {
 
1859
        if (translate_frm(&copy))
 
1860
        {
 
1861
          err << "Create table " << table.getTableName() << " failed: ";
 
1862
          err << "Translate frm error" << endl;
 
1863
          return false;
 
1864
        }
 
1865
      }
 
1866
      copy.setFragmentData(new_array.getBase(), no_parts);
 
1867
    }
 
1868
 
 
1869
    /**
 
1870
     * Force of varpart was introduced in 5.1.18, telco 6.1.7 and 6.2.1
 
1871
     * Since default from mysqld is to add force of varpart (disable with
 
1872
     * ROW_FORMAT=FIXED) we force varpart onto tables when they are restored
 
1873
     * from backups taken with older versions. This will be wrong if
 
1874
     * ROW_FORMAT=FIXED was used on original table, however the likelyhood of
 
1875
     * this is low, since ROW_FORMAT= was a NOOP in older versions.
 
1876
     */
 
1877
 
 
1878
    if (table.getBackupVersion() < MAKE_VERSION(5,1,18))
 
1879
      copy.setForceVarPart(true);
 
1880
    else if (getMajor(table.getBackupVersion()) == 6 &&
 
1881
             (table.getBackupVersion() < MAKE_VERSION(6,1,7) ||
 
1882
              table.getBackupVersion() == MAKE_VERSION(6,2,0)))
 
1883
      copy.setForceVarPart(true);
 
1884
 
 
1885
    /*
 
1886
      update min and max rows to reflect the table, this to
 
1887
      ensure that memory is allocated properly in the ndb kernel
 
1888
    */
 
1889
    copy.setMinRows(table.getNoOfRecords());
 
1890
    if (table.getNoOfRecords() > copy.getMaxRows())
 
1891
    {
 
1892
      copy.setMaxRows(table.getNoOfRecords());
 
1893
    }
 
1894
    
 
1895
    NdbTableImpl &tableImpl = NdbTableImpl::getImpl(copy);
 
1896
    if (table.getBackupVersion() < MAKE_VERSION(5,1,0) && !m_no_upgrade){
 
1897
      for(int i= 0; i < copy.getNoOfColumns(); i++)
 
1898
      {
 
1899
        NdbDictionary::Column::Type t = copy.getColumn(i)->getType();
 
1900
 
 
1901
        if (t == NdbDictionary::Column::Varchar ||
 
1902
          t == NdbDictionary::Column::Varbinary)
 
1903
          tableImpl.getColumn(i)->setArrayType(NdbDictionary::Column::ArrayTypeShortVar);
 
1904
        if (t == NdbDictionary::Column::Longvarchar ||
 
1905
          t == NdbDictionary::Column::Longvarbinary)
 
1906
          tableImpl.getColumn(i)->setArrayType(NdbDictionary::Column::ArrayTypeMediumVar);
 
1907
      }
 
1908
    }
 
1909
 
 
1910
    if (dict->createTable(copy) == -1) 
 
1911
    {
 
1912
      err << "Create table `" << table.getTableName() << "` failed: "
 
1913
          << dict->getNdbError() << endl;
 
1914
      if (dict->getNdbError().code == 771)
 
1915
      {
 
1916
        /*
 
1917
          The user on the cluster where the backup was created had specified
 
1918
          specific node groups for partitions. Some of these node groups
 
1919
          didn't exist on this cluster. We will warn the user of this and
 
1920
          inform him of his option.
 
1921
        */
 
1922
        err << "The node groups defined in the table didn't exist in this";
 
1923
        err << " cluster." << endl << "There is an option to use the";
 
1924
        err << " the parameter ndb-nodegroup-map to define a mapping from";
 
1925
        err << endl << "the old nodegroups to new nodegroups" << endl; 
 
1926
      }
 
1927
      return false;
 
1928
    }
 
1929
    info.setLevel(254);
 
1930
    info << "Successfully restored table `"
 
1931
         << table.getTableName() << "`" << endl;
 
1932
  }  
 
1933
  
 
1934
  const NdbDictionary::Table* tab = dict->getTable(table_name.c_str());
 
1935
  if(tab == 0){
 
1936
    err << "Unable to find table: `" << table_name << "`" << endl;
 
1937
    return false;
 
1938
  }
 
1939
  if(m_restore_meta)
 
1940
  {
 
1941
    if (tab->getFrmData())
 
1942
    {
 
1943
      // a MySQL Server table is restored, thus an event should be created
 
1944
      BaseString event_name("REPL$");
 
1945
      event_name.append(db_name.c_str());
 
1946
      event_name.append("/");
 
1947
      event_name.append(table_name.c_str());
 
1948
 
 
1949
      NdbDictionary::Event my_event(event_name.c_str());
 
1950
      my_event.setTable(*tab);
 
1951
      my_event.addTableEvent(NdbDictionary::Event::TE_ALL);
 
1952
      my_event.setReport(NdbDictionary::Event::ER_DDL);
 
1953
 
 
1954
      // add all columns to the event
 
1955
      bool has_blobs = false;
 
1956
      for(int a= 0; a < tab->getNoOfColumns(); a++)
 
1957
      {
 
1958
        my_event.addEventColumn(a);
 
1959
        NdbDictionary::Column::Type t = tab->getColumn(a)->getType();
 
1960
        if (t == NdbDictionary::Column::Blob ||
 
1961
            t == NdbDictionary::Column::Text)
 
1962
          has_blobs = true;
 
1963
      }
 
1964
      if (has_blobs)
 
1965
        my_event.mergeEvents(true);
 
1966
 
 
1967
      while ( dict->createEvent(my_event) ) // Add event to database
 
1968
      {
 
1969
        if (dict->getNdbError().classification == NdbError::SchemaObjectExists)
 
1970
        {
 
1971
          info << "Event for table " << table.getTableName()
 
1972
               << " already exists, removing.\n";
 
1973
          if (!dict->dropEvent(my_event.getName(), 1))
 
1974
            continue;
 
1975
        }
 
1976
        err << "Create table event for " << table.getTableName() << " failed: "
 
1977
            << dict->getNdbError() << endl;
 
1978
        dict->dropTable(table_name.c_str());
 
1979
        return false;
 
1980
      }
 
1981
      info.setLevel(254);
 
1982
      info << "Successfully restored table event " << event_name << endl ;
 
1983
    }
 
1984
  }
 
1985
  const NdbDictionary::Table* null = 0;
 
1986
  m_new_tables.fill(table.m_dictTable->getTableId(), null);
 
1987
  m_new_tables[table.m_dictTable->getTableId()] = tab;
 
1988
 
 
1989
  m_n_tables++;
 
1990
 
 
1991
  return true;
 
1992
}
 
1993
 
 
1994
bool
 
1995
BackupRestore::endOfTables(){
 
1996
  if(!m_restore_meta && !m_rebuild_indexes && !m_disable_indexes)
 
1997
    return true;
 
1998
 
 
1999
  NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
 
2000
  for(size_t i = 0; i<m_indexes.size(); i++){
 
2001
    NdbTableImpl & indtab = NdbTableImpl::getImpl(* m_indexes[i]);
 
2002
 
 
2003
    BaseString db_name, schema_name, table_name;
 
2004
    if (!dissect_table_name(indtab.m_primaryTable.c_str(),
 
2005
                            db_name, schema_name, table_name)) {
 
2006
      return false;
 
2007
    }
 
2008
    check_rewrite_database(db_name);
 
2009
 
 
2010
    m_ndb->setDatabaseName(db_name.c_str());
 
2011
    m_ndb->setSchemaName(schema_name.c_str());
 
2012
 
 
2013
    const NdbDictionary::Table * prim = dict->getTable(table_name.c_str());
 
2014
    if(prim == 0){
 
2015
      err << "Unable to find base table `" << table_name
 
2016
          << "` for index `"
 
2017
          << indtab.getName() << "`" << endl;
 
2018
      if (ga_skip_broken_objects)
 
2019
      {
 
2020
        continue;
 
2021
      }
 
2022
      return false;
 
2023
    }
 
2024
    NdbTableImpl& base = NdbTableImpl::getImpl(*prim);
 
2025
    NdbIndexImpl* idx;
 
2026
    Vector<BaseString> split_idx;
 
2027
    {
 
2028
      BaseString tmp(indtab.getName());
 
2029
      if (tmp.split(split_idx, "/") != 4)
 
2030
      {
 
2031
        err << "Invalid index name format `" << indtab.getName() << "`" << endl;
 
2032
        return false;
 
2033
      }
 
2034
    }
 
2035
    if(NdbDictInterface::create_index_obj_from_table(&idx, &indtab, &base))
 
2036
    {
 
2037
      err << "Failed to create index `" << split_idx[3]
 
2038
          << "` on " << table_name << endl;
 
2039
        return false;
 
2040
    }
 
2041
    idx->setName(split_idx[3].c_str());
 
2042
    if (m_restore_meta && !m_disable_indexes && !m_rebuild_indexes)
 
2043
    {
 
2044
      if (dict->createIndex(* idx) != 0)
 
2045
      {
 
2046
        delete idx;
 
2047
        err << "Failed to create index `" << split_idx[3].c_str()
 
2048
            << "` on `" << table_name << "`" << endl
 
2049
            << dict->getNdbError() << endl;
 
2050
 
 
2051
        return false;
 
2052
      }
 
2053
      info << "Successfully created index `" << split_idx[3].c_str()
 
2054
          << "` on `" << table_name << "`" << endl;
 
2055
    }
 
2056
    else if (m_disable_indexes)
 
2057
    {
 
2058
      int res = dict->dropIndex(idx->getName(), prim->getName());
 
2059
      if (res == 0)
 
2060
      {
 
2061
        info << "Dropped index `" << split_idx[3].c_str()
 
2062
            << "` on `" << table_name << "`" << endl;
 
2063
      }
 
2064
    }
 
2065
    Uint32 id = prim->getObjectId();
 
2066
    if (m_index_per_table.size() <= id)
 
2067
    {
 
2068
      Vector<NdbDictionary::Index*> tmp;
 
2069
      m_index_per_table.fill(id + 1, tmp);
 
2070
    }
 
2071
    Vector<NdbDictionary::Index*> & list = m_index_per_table[id];
 
2072
    list.push_back(idx);
 
2073
  }
 
2074
  return true;
 
2075
}
 
2076
 
 
2077
void BackupRestore::tuple(const TupleS & tup, Uint32 fragmentId)
 
2078
{
 
2079
  const TableS * tab = tup.getTable();
 
2080
 
 
2081
  if (!m_restore) 
 
2082
    return;
 
2083
 
 
2084
  while (m_free_callback == 0)
 
2085
  {
 
2086
    assert(m_transactions == m_parallelism);
 
2087
    // send-poll all transactions
 
2088
    // close transaction is done in callback
 
2089
    m_ndb->sendPollNdb(3000, 1);
 
2090
  }
 
2091
  
 
2092
  restore_callback_t * cb = m_free_callback;
 
2093
  
 
2094
  if (cb == 0)
 
2095
    assert(false);
 
2096
  
 
2097
  cb->retries = 0;
 
2098
  cb->fragId = fragmentId;
 
2099
  cb->tup = tup; // must do copy!
 
2100
 
 
2101
  if (tab->isSYSTAB_0())
 
2102
  {
 
2103
    tuple_SYSTAB_0(cb, *tab);
 
2104
    return;
 
2105
  }
 
2106
 
 
2107
  m_free_callback = cb->next;
 
2108
 
 
2109
  tuple_a(cb);
 
2110
}
 
2111
 
 
2112
void BackupRestore::tuple_a(restore_callback_t *cb)
 
2113
{
 
2114
  Uint32 partition_id = cb->fragId;
 
2115
  Uint32 n_bytes;
 
2116
  while (cb->retries < 10) 
 
2117
  {
 
2118
    /**
 
2119
     * start transactions
 
2120
     */
 
2121
    cb->connection = m_ndb->startTransaction();
 
2122
    if (cb->connection == NULL) 
 
2123
    {
 
2124
      if (errorHandler(cb)) 
 
2125
      {
 
2126
        m_ndb->sendPollNdb(3000, 1);
 
2127
        continue;
 
2128
      }
 
2129
      err << "Cannot start transaction" << endl;
 
2130
      exitHandler();
 
2131
    } // if
 
2132
    
 
2133
    const TupleS &tup = cb->tup;
 
2134
    const NdbDictionary::Table * table = get_table(tup.getTable()->m_dictTable);
 
2135
 
 
2136
    NdbOperation * op = cb->connection->getNdbOperation(table);
 
2137
    
 
2138
    if (op == NULL) 
 
2139
    {
 
2140
      if (errorHandler(cb)) 
 
2141
        continue;
 
2142
      err << "Cannot get operation: " << cb->connection->getNdbError() << endl;
 
2143
      exitHandler();
 
2144
    } // if
 
2145
    
 
2146
    if (op->writeTuple() == -1) 
 
2147
    {
 
2148
      if (errorHandler(cb))
 
2149
        continue;
 
2150
      err << "Error defining op: " << cb->connection->getNdbError() << endl;
 
2151
      exitHandler();
 
2152
    } // if
 
2153
 
 
2154
    n_bytes= 0;
 
2155
 
 
2156
    if (table->getFragmentType() == NdbDictionary::Object::UserDefined)
 
2157
    {
 
2158
      if (table->getDefaultNoPartitionsFlag())
 
2159
      {
 
2160
        /*
 
2161
          This can only happen for HASH partitioning with
 
2162
          user defined hash function where user hasn't
 
2163
          specified the number of partitions and we
 
2164
          have to calculate it. We use the hash value
 
2165
          stored in the record to calculate the partition
 
2166
          to use.
 
2167
        */
 
2168
        int i = tup.getNoOfAttributes() - 1;
 
2169
        const AttributeData  *attr_data = tup.getData(i);
 
2170
        Uint32 hash_value =  *attr_data->u_int32_value;
 
2171
        op->setPartitionId(get_part_id(table, hash_value));
 
2172
      }
 
2173
      else
 
2174
      {
 
2175
        /*
 
2176
          Either RANGE or LIST (with or without subparts)
 
2177
          OR HASH partitioning with user defined hash
 
2178
          function but with fixed set of partitions.
 
2179
        */
 
2180
        op->setPartitionId(partition_id);
 
2181
      }
 
2182
    }
 
2183
    int ret = 0;
 
2184
    for (int j = 0; j < 2; j++)
 
2185
    {
 
2186
      for (int i = 0; i < tup.getNoOfAttributes(); i++) 
 
2187
      {
 
2188
        AttributeDesc * attr_desc = tup.getDesc(i);
 
2189
        const AttributeData * attr_data = tup.getData(i);
 
2190
        int size = attr_desc->size;
 
2191
        int arraySize = attr_desc->arraySize;
 
2192
        char * dataPtr = attr_data->string_value;
 
2193
        Uint32 length = 0;
 
2194
 
 
2195
        if (attr_desc->m_exclude)
 
2196
          continue;
 
2197
       
 
2198
        if (!attr_data->null)
 
2199
        {
 
2200
          const unsigned char * src = (const unsigned char *)dataPtr;
 
2201
          switch(attr_desc->m_column->getType()){
 
2202
          case NdbDictionary::Column::Varchar:
 
2203
          case NdbDictionary::Column::Varbinary:
 
2204
            length = src[0] + 1;
 
2205
            break;
 
2206
          case NdbDictionary::Column::Longvarchar:
 
2207
          case NdbDictionary::Column::Longvarbinary:
 
2208
            length = src[0] + (src[1] << 8) + 2;
 
2209
            break;
 
2210
          default:
 
2211
            length = attr_data->size;
 
2212
            break;
 
2213
          }
 
2214
        }
 
2215
        if (j == 0 && tup.getTable()->have_auto_inc(i))
 
2216
          tup.getTable()->update_max_auto_val(dataPtr,size*arraySize);
 
2217
        
 
2218
        if (attr_desc->convertFunc)
 
2219
        {
 
2220
          if ((attr_desc->m_column->getPrimaryKey() && j == 0) ||
 
2221
              (j == 1 && !attr_data->null))
 
2222
          {
 
2223
            bool truncated = true; // assume data truncation until overridden
 
2224
            dataPtr = (char*)attr_desc->convertFunc(dataPtr,
 
2225
                                                    attr_desc->parameter,
 
2226
                                                    truncated);
 
2227
            if (!dataPtr)
 
2228
            {
 
2229
              err << "Error: Convert data failed when restoring tuples!" << endl;
 
2230
              exitHandler();
 
2231
            }
 
2232
            if (truncated)
 
2233
            {
 
2234
              // wl5421: option to report data truncation on tuple of desired
 
2235
              //err << "======  data truncation detected for column: "
 
2236
              //    << attr_desc->m_column->getName() << endl;
 
2237
              attr_desc->truncation_detected = true;
 
2238
            }
 
2239
          }            
 
2240
        }
 
2241
 
 
2242
        if (attr_desc->m_column->getPrimaryKey())
 
2243
        {
 
2244
          if (j == 1) continue;
 
2245
          ret = op->equal(attr_desc->attrId, dataPtr, length);
 
2246
        }
 
2247
        else
 
2248
        {
 
2249
          if (j == 0) continue;
 
2250
          if (attr_data->null) 
 
2251
            ret = op->setValue(attr_desc->attrId, NULL, 0);
 
2252
          else
 
2253
            ret = op->setValue(attr_desc->attrId, dataPtr, length);
 
2254
        }
 
2255
        if (ret < 0) {
 
2256
          ndbout_c("Column: %d type %d %d %d %d",i,
 
2257
                   attr_desc->m_column->getType(),
 
2258
                   size, arraySize, length);
 
2259
          break;
 
2260
        }
 
2261
        n_bytes+= length;
 
2262
      }
 
2263
      if (ret < 0)
 
2264
        break;
 
2265
    }
 
2266
    if (ret < 0)
 
2267
    {
 
2268
      if (errorHandler(cb)) 
 
2269
        continue;
 
2270
      err << "Error defining op: " << cb->connection->getNdbError() << endl;
 
2271
      exitHandler();
 
2272
    }
 
2273
 
 
2274
    if (opt_no_binlog)
 
2275
    {
 
2276
      op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
 
2277
    }
 
2278
 
 
2279
    // Prepare transaction (the transaction is NOT yet sent to NDB)
 
2280
    cb->n_bytes= n_bytes;
 
2281
    cb->connection->executeAsynchPrepare(NdbTransaction::Commit,
 
2282
                                         &callback, cb);
 
2283
    m_transactions++;
 
2284
    return;
 
2285
  }
 
2286
  err << "Retried transaction " << cb->retries << " times.\nLast error"
 
2287
      << m_ndb->getNdbError(cb->error_code) << endl
 
2288
      << "...Unable to recover from errors. Exiting..." << endl;
 
2289
  exitHandler();
 
2290
}
 
2291
 
 
2292
void BackupRestore::tuple_SYSTAB_0(restore_callback_t *cb,
 
2293
                                   const TableS & tab)
 
2294
{
 
2295
  const TupleS & tup = cb->tup;
 
2296
  Uint32 syskey;
 
2297
  Uint64 nextid;
 
2298
 
 
2299
  if (tab.get_auto_data(tup, &syskey, &nextid))
 
2300
  {
 
2301
    /*
 
2302
      We found a valid auto_increment value in SYSTAB_0
 
2303
      where syskey is a table_id and nextid is next auto_increment
 
2304
      value.
 
2305
     */
 
2306
    if (restoreAutoIncrement(cb, syskey, nextid) ==  -1)
 
2307
      exitHandler();
 
2308
  }
 
2309
}
 
2310
 
 
2311
int BackupRestore::restoreAutoIncrement(restore_callback_t *cb,
 
2312
                                        Uint32 tableId, Uint64 value)
 
2313
{
 
2314
  /*
 
2315
    Restore the auto_increment value found in SYSTAB_0 from
 
2316
    backup. First map the old table id to the new table while
 
2317
    also checking that it is an actual table will some auto_increment
 
2318
    column. Note that the SYSTAB_0 table in the backup can contain
 
2319
    stale information from dropped tables.
 
2320
   */
 
2321
  int result = 0;
 
2322
  const NdbDictionary::Table* tab = (tableId < m_new_tables.size())? m_new_tables[tableId] : NULL;
 
2323
  if (tab && tab->getNoOfAutoIncrementColumns() > 0)
 
2324
  {
 
2325
    /*
 
2326
      Write the auto_increment value back into SYSTAB_0.
 
2327
      This is done in a separate transaction and could possibly
 
2328
      fail, so we retry if a temporary error is received.
 
2329
     */
 
2330
    while (cb->retries < 10)
 
2331
    {
 
2332
      if ((result = m_ndb->setAutoIncrementValue(tab, value, false) == -1))
 
2333
      {
 
2334
        if (errorHandler(cb)) 
 
2335
        {
 
2336
          continue;
 
2337
        }
 
2338
      }
 
2339
      break;
 
2340
    }
 
2341
  }
 
2342
  return result;
 
2343
}
 
2344
 
 
2345
void BackupRestore::cback(int result, restore_callback_t *cb)
 
2346
{
 
2347
  m_transactions--;
 
2348
 
 
2349
  if (result < 0)
 
2350
  {
 
2351
    /**
 
2352
     * Error. temporary or permanent?
 
2353
     */
 
2354
    if (errorHandler(cb))
 
2355
      tuple_a(cb); // retry
 
2356
    else
 
2357
    {
 
2358
      err << "Restore: Failed to restore data due to a unrecoverable error. Exiting..." << endl;
 
2359
      exitHandler();
 
2360
    }
 
2361
  }
 
2362
  else
 
2363
  {
 
2364
    /**
 
2365
     * OK! close transaction
 
2366
     */
 
2367
    m_ndb->closeTransaction(cb->connection);
 
2368
    cb->connection= 0;
 
2369
    cb->next= m_free_callback;
 
2370
    m_free_callback= cb;
 
2371
    m_dataBytes+= cb->n_bytes;
 
2372
    m_dataCount++;
 
2373
  }
 
2374
}
 
2375
 
 
2376
/**
 
2377
 * returns true if is recoverable,
 
2378
 * Error handling based on hugo
 
2379
 *  false if it is an  error that generates an abort.
 
2380
 */
 
2381
bool BackupRestore::errorHandler(restore_callback_t *cb) 
 
2382
{
 
2383
  NdbError error;
 
2384
  if(cb->connection)
 
2385
  {
 
2386
    error= cb->connection->getNdbError();
 
2387
    m_ndb->closeTransaction(cb->connection);
 
2388
    cb->connection= 0;
 
2389
  }
 
2390
  else
 
2391
  {
 
2392
    error= m_ndb->getNdbError();
 
2393
  } 
 
2394
 
 
2395
  Uint32 sleepTime = 100 + cb->retries * 300;
 
2396
  
 
2397
  cb->retries++;
 
2398
  cb->error_code = error.code;
 
2399
 
 
2400
  switch(error.status)
 
2401
  {
 
2402
  case NdbError::Success:
 
2403
    err << "Success error: " << error << endl;
 
2404
    return false;
 
2405
    // ERROR!
 
2406
    
 
2407
  case NdbError::TemporaryError:
 
2408
    err << "Temporary error: " << error << endl;
 
2409
    m_temp_error = true;
 
2410
    NdbSleep_MilliSleep(sleepTime);
 
2411
    return true;
 
2412
    // RETRY
 
2413
    
 
2414
  case NdbError::UnknownResult:
 
2415
    err << "Unknown: " << error << endl;
 
2416
    return false;
 
2417
    // ERROR!
 
2418
    
 
2419
  default:
 
2420
  case NdbError::PermanentError:
 
2421
    //ERROR
 
2422
    err << "Permanent: " << error << endl;
 
2423
    return false;
 
2424
  }
 
2425
  err << "No error status" << endl;
 
2426
  return false;
 
2427
}
 
2428
 
 
2429
void BackupRestore::exitHandler() 
 
2430
{
 
2431
  release();
 
2432
  NDBT_ProgramExit(NDBT_FAILED);
 
2433
  exit(NDBT_FAILED);
 
2434
}
 
2435
 
 
2436
 
 
2437
void
 
2438
BackupRestore::tuple_free()
 
2439
{
 
2440
  if (!m_restore)
 
2441
    return;
 
2442
 
 
2443
  // Poll all transactions
 
2444
  while (m_transactions)
 
2445
  {
 
2446
    m_ndb->sendPollNdb(3000);
 
2447
  }
 
2448
}
 
2449
 
 
2450
void
 
2451
BackupRestore::endOfTuples()
 
2452
{
 
2453
  tuple_free();
 
2454
}
 
2455
 
 
2456
#ifdef NOT_USED
 
2457
static bool use_part_id(const NdbDictionary::Table *table)
 
2458
{
 
2459
  if (table->getDefaultNoPartitionsFlag() &&
 
2460
      (table->getFragmentType() == NdbDictionary::Object::UserDefined))
 
2461
    return false;
 
2462
  else
 
2463
    return true;
 
2464
}
 
2465
#endif
 
2466
 
 
2467
static Uint32 get_part_id(const NdbDictionary::Table *table,
 
2468
                          Uint32 hash_value)
 
2469
{
 
2470
  Uint32 no_frags = table->getFragmentCount();
 
2471
  
 
2472
  if (table->getLinearFlag())
 
2473
  {
 
2474
    Uint32 part_id;
 
2475
    Uint32 mask = 1;
 
2476
    while (no_frags > mask) mask <<= 1;
 
2477
    mask--;
 
2478
    part_id = hash_value & mask;
 
2479
    if (part_id >= no_frags)
 
2480
      part_id = hash_value & (mask >> 1);
 
2481
    return part_id;
 
2482
  }
 
2483
  else
 
2484
    return (hash_value % no_frags);
 
2485
}
 
2486
 
 
2487
struct TransGuard
 
2488
{
 
2489
  NdbTransaction* pTrans;
 
2490
  TransGuard(NdbTransaction* p) : pTrans(p) {}
 
2491
  ~TransGuard() { if (pTrans) pTrans->close();}
 
2492
};
 
2493
 
 
2494
void
 
2495
BackupRestore::logEntry(const LogEntry & tup)
 
2496
{
 
2497
  if (!m_restore)
 
2498
    return;
 
2499
 
 
2500
 
 
2501
  Uint32 retries = 0;
 
2502
  NdbError errobj;
 
2503
retry:
 
2504
  if (retries == 11)
 
2505
  {
 
2506
    err << "execute failed: " << errobj << endl;
 
2507
    exitHandler();
 
2508
  }
 
2509
  else if (retries > 0)
 
2510
  {
 
2511
    NdbSleep_MilliSleep(100 + (retries - 1) * 100);
 
2512
  }
 
2513
  
 
2514
  retries++;
 
2515
 
 
2516
  NdbTransaction * trans = m_ndb->startTransaction();
 
2517
  if (trans == NULL) 
 
2518
  {
 
2519
    errobj = m_ndb->getNdbError();
 
2520
    if (errobj.status == NdbError::TemporaryError)
 
2521
    {
 
2522
      goto retry;
 
2523
    }
 
2524
    err << "Cannot start transaction: " << errobj << endl;
 
2525
    exitHandler();
 
2526
  } // if
 
2527
  
 
2528
  TransGuard g(trans);
 
2529
  const NdbDictionary::Table * table = get_table(tup.m_table->m_dictTable);
 
2530
  NdbOperation * op = trans->getNdbOperation(table);
 
2531
  if (op == NULL) 
 
2532
  {
 
2533
    err << "Cannot get operation: " << trans->getNdbError() << endl;
 
2534
    exitHandler();
 
2535
  } // if
 
2536
  
 
2537
  int check = 0;
 
2538
  switch(tup.m_type)
 
2539
  {
 
2540
  case LogEntry::LE_INSERT:
 
2541
    check = op->insertTuple();
 
2542
    break;
 
2543
  case LogEntry::LE_UPDATE:
 
2544
    check = op->updateTuple();
 
2545
    break;
 
2546
  case LogEntry::LE_DELETE:
 
2547
    check = op->deleteTuple();
 
2548
    break;
 
2549
  default:
 
2550
    err << "Log entry has wrong operation type."
 
2551
           << " Exiting...";
 
2552
    exitHandler();
 
2553
  }
 
2554
 
 
2555
  if (check != 0) 
 
2556
  {
 
2557
    err << "Error defining op: " << trans->getNdbError() << endl;
 
2558
    exitHandler();
 
2559
  } // if
 
2560
 
 
2561
  if (table->getFragmentType() == NdbDictionary::Object::UserDefined)
 
2562
  {
 
2563
    if (table->getDefaultNoPartitionsFlag())
 
2564
    {
 
2565
      const AttributeS * attr = tup[tup.size()-1];
 
2566
      Uint32 hash_value = *(Uint32*)attr->Data.string_value;
 
2567
      op->setPartitionId(get_part_id(table, hash_value));
 
2568
    }
 
2569
    else
 
2570
      op->setPartitionId(tup.m_frag_id);
 
2571
  }
 
2572
 
 
2573
  Bitmask<4096> keys;
 
2574
  Uint32 n_bytes= 0;
 
2575
  for (Uint32 i= 0; i < tup.size(); i++) 
 
2576
  {
 
2577
    const AttributeS * attr = tup[i];
 
2578
    int size = attr->Desc->size;
 
2579
    int arraySize = attr->Desc->arraySize;
 
2580
    const char * dataPtr = attr->Data.string_value;
 
2581
 
 
2582
    if (attr->Desc->m_exclude)
 
2583
      continue;
 
2584
    
 
2585
    if (tup.m_table->have_auto_inc(attr->Desc->attrId))
 
2586
      tup.m_table->update_max_auto_val(dataPtr,size*arraySize);
 
2587
 
 
2588
    const Uint32 length = (size / 8) * arraySize;
 
2589
    n_bytes+= length;
 
2590
 
 
2591
    if (attr->Desc->convertFunc)
 
2592
    {
 
2593
      bool truncated = true; // assume data truncation until overridden
 
2594
      dataPtr = (char*)attr->Desc->convertFunc(dataPtr,
 
2595
                                               attr->Desc->parameter,
 
2596
                                               truncated);
 
2597
      if (!dataPtr)
 
2598
      {
 
2599
        err << "Error: Convert data failed when restoring tuples!" << endl;
 
2600
        exitHandler();
 
2601
      }            
 
2602
      if (truncated)
 
2603
      {
 
2604
        // wl5421: option to report data truncation on tuple of desired
 
2605
        //err << "******  data truncation detected for column: "
 
2606
        //    << attr->Desc->m_column->getName() << endl;
 
2607
        attr->Desc->truncation_detected = true;
 
2608
      }
 
2609
    } 
 
2610
 
 
2611
    if (attr->Desc->m_column->getPrimaryKey())
 
2612
    {
 
2613
      if(!keys.get(attr->Desc->attrId))
 
2614
      {
 
2615
        keys.set(attr->Desc->attrId);
 
2616
        check= op->equal(attr->Desc->attrId, dataPtr, length);
 
2617
      }
 
2618
    }
 
2619
    else
 
2620
      check= op->setValue(attr->Desc->attrId, dataPtr, length);
 
2621
    
 
2622
    if (check != 0) 
 
2623
    {
 
2624
      err << "Error defining op: " << trans->getNdbError() << endl;
 
2625
      exitHandler();
 
2626
    } // if
 
2627
  }
 
2628
  
 
2629
  if (opt_no_binlog)
 
2630
  {
 
2631
    op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
 
2632
  }
 
2633
  const int ret = trans->execute(NdbTransaction::Commit);
 
2634
  if (ret != 0)
 
2635
  {
 
2636
    // Both insert update and delete can fail during log running
 
2637
    // and it's ok
 
2638
    bool ok= false;
 
2639
    errobj= trans->getNdbError();
 
2640
    if (errobj.status == NdbError::TemporaryError)
 
2641
      goto retry;
 
2642
 
 
2643
    switch(tup.m_type)
 
2644
    {
 
2645
    case LogEntry::LE_INSERT:
 
2646
      if(errobj.status == NdbError::PermanentError &&
 
2647
         errobj.classification == NdbError::ConstraintViolation)
 
2648
        ok= true;
 
2649
      break;
 
2650
    case LogEntry::LE_UPDATE:
 
2651
    case LogEntry::LE_DELETE:
 
2652
      if(errobj.status == NdbError::PermanentError &&
 
2653
         errobj.classification == NdbError::NoDataFound)
 
2654
        ok= true;
 
2655
      break;
 
2656
    }
 
2657
    if (!ok)
 
2658
    {
 
2659
      err << "execute failed: " << errobj << endl;
 
2660
      exitHandler();
 
2661
    }
 
2662
  }
 
2663
  
 
2664
  m_logBytes+= n_bytes;
 
2665
  m_logCount++;
 
2666
}
 
2667
 
 
2668
void
 
2669
BackupRestore::endOfLogEntrys()
 
2670
{
 
2671
  if (!m_restore)
 
2672
    return;
 
2673
 
 
2674
  info.setLevel(254);
 
2675
  info << "Restored " << m_dataCount << " tuples and "
 
2676
       << m_logCount << " log entries" << endl;
 
2677
}
 
2678
 
 
2679
/*
 
2680
 *   callback : This is called when the transaction is polled
 
2681
 *              
 
2682
 *   (This function must have three arguments: 
 
2683
 *   - The result of the transaction, 
 
2684
 *   - The NdbTransaction object, and 
 
2685
 *   - A pointer to an arbitrary object.)
 
2686
 */
 
2687
 
 
2688
static void
 
2689
callback(int result, NdbTransaction* trans, void* aObject)
 
2690
{
 
2691
  restore_callback_t *cb = (restore_callback_t *)aObject;
 
2692
  (cb->restore)->cback(result, cb);
 
2693
}
 
2694
 
 
2695
 
 
2696
AttrCheckCompatFunc 
 
2697
BackupRestore::get_attr_check_compatability(const NDBCOL::Type &old_type, 
 
2698
                                            const NDBCOL::Type &new_type) 
 
2699
{
 
2700
  int i = 0;
 
2701
  NDBCOL::Type first_item = m_allowed_promotion_attrs[0].old_type;
 
2702
  NDBCOL::Type second_item = m_allowed_promotion_attrs[0].new_type;
 
2703
 
 
2704
  while (first_item != old_type || second_item != new_type) 
 
2705
  {
 
2706
    if (first_item == NDBCOL::Undefined)
 
2707
      break;
 
2708
 
 
2709
    i++;
 
2710
    first_item = m_allowed_promotion_attrs[i].old_type;
 
2711
    second_item = m_allowed_promotion_attrs[i].new_type;
 
2712
  }
 
2713
  if (first_item == old_type && second_item == new_type)
 
2714
    return m_allowed_promotion_attrs[i].attr_check_compatability;
 
2715
  return  NULL;
 
2716
}
 
2717
 
 
2718
AttrConvertFunc
 
2719
BackupRestore::get_convert_func(const NDBCOL::Type &old_type, 
 
2720
                                const NDBCOL::Type &new_type) 
 
2721
{
 
2722
  int i = 0;
 
2723
  NDBCOL::Type first_item = m_allowed_promotion_attrs[0].old_type;
 
2724
  NDBCOL::Type second_item = m_allowed_promotion_attrs[0].new_type;
 
2725
 
 
2726
  while (first_item != old_type || second_item != new_type)
 
2727
  {
 
2728
    if (first_item == NDBCOL::Undefined)
 
2729
      break;
 
2730
    i++;
 
2731
    first_item = m_allowed_promotion_attrs[i].old_type;
 
2732
    second_item = m_allowed_promotion_attrs[i].new_type;
 
2733
  }
 
2734
  if (first_item == old_type && second_item == new_type)
 
2735
    return m_allowed_promotion_attrs[i].attr_convert;
 
2736
 
 
2737
  return  NULL;
 
2738
 
 
2739
}
 
2740
 
 
2741
AttrConvType
 
2742
BackupRestore::check_compat_promotion(const NDBCOL &old_col,
 
2743
                                      const NDBCOL &new_col)
 
2744
{
 
2745
  return ACT_PRESERVING;
 
2746
}
 
2747
 
 
2748
AttrConvType
 
2749
BackupRestore::check_compat_lossy(const NDBCOL &old_col,
 
2750
                                  const NDBCOL &new_col)
 
2751
{
 
2752
  return ACT_LOSSY;
 
2753
}
 
2754
 
 
2755
AttrConvType
 
2756
BackupRestore::check_compat_sizes(const NDBCOL &old_col,
 
2757
                                  const NDBCOL &new_col)
 
2758
{
 
2759
  // the size (width) of the element type
 
2760
  Uint32 new_size = new_col.getSize();
 
2761
  Uint32 old_size = old_col.getSize();
 
2762
  // the fixed/max array length (1 for scalars)
 
2763
  Uint32 new_length = new_col.getLength();
 
2764
  Uint32 old_length = old_col.getLength();
 
2765
 
 
2766
  // identity conversions have been handled by column_compatible_check()
 
2767
  assert(new_size != old_size
 
2768
         || new_length != old_length
 
2769
         || new_col.getArrayType() != old_col.getArrayType());
 
2770
 
 
2771
  // test for loss of element width or array length
 
2772
  if (new_size < old_size || new_length < old_length) {
 
2773
    return ACT_LOSSY;
 
2774
  }
 
2775
 
 
2776
  // not tested: conversions varying in both, array length and element width
 
2777
  if (new_size != old_size && new_length != old_length) {
 
2778
    return ACT_UNSUPPORTED;
 
2779
  }
 
2780
 
 
2781
  assert(new_size >= old_size && new_length >= old_length);
 
2782
  return ACT_PRESERVING;
 
2783
}
 
2784
 
 
2785
// ----------------------------------------------------------------------
 
2786
// explicit template instantiations
 
2787
// ----------------------------------------------------------------------
 
2788
 
 
2789
template class Vector<NdbDictionary::Table*>;
 
2790
template class Vector<const NdbDictionary::Table*>;
 
2791
template class Vector<NdbDictionary::Tablespace*>;
 
2792
template class Vector<NdbDictionary::LogfileGroup*>;
 
2793
template class Vector<NdbDictionary::HashMap*>;
 
2794
template class Vector<NdbDictionary::Index*>;
 
2795
template class Vector<Vector<NdbDictionary::Index*> >;
 
2796
 
 
2797
// char array promotions/demotions
 
2798
template void * BackupRestore::convert_array< Hchar, Hchar >(const void *, void *, bool &);
 
2799
template void * BackupRestore::convert_array< Hchar, Hvarchar >(const void *, void *, bool &);
 
2800
template void * BackupRestore::convert_array< Hchar, Hlongvarchar >(const void *, void *, bool &);
 
2801
template void * BackupRestore::convert_array< Hvarchar, Hchar >(const void *, void *, bool &);
 
2802
template void * BackupRestore::convert_array< Hvarchar, Hvarchar >(const void *, void *, bool &);
 
2803
template void * BackupRestore::convert_array< Hvarchar, Hlongvarchar >(const void *, void *, bool &);
 
2804
template void * BackupRestore::convert_array< Hlongvarchar, Hchar >(const void *, void *, bool &);
 
2805
template void * BackupRestore::convert_array< Hlongvarchar, Hvarchar >(const void *, void *, bool &);
 
2806
template void * BackupRestore::convert_array< Hlongvarchar, Hlongvarchar >(const void *, void *, bool &);
 
2807
 
 
2808
// binary array promotions/demotions
 
2809
template void * BackupRestore::convert_array< Hbinary, Hbinary >(const void *, void *, bool &);
 
2810
template void * BackupRestore::convert_array< Hbinary, Hvarbinary >(const void *, void *, bool &);
 
2811
template void * BackupRestore::convert_array< Hbinary, Hlongvarbinary >(const void *, void *, bool &);
 
2812
template void * BackupRestore::convert_array< Hvarbinary, Hbinary >(const void *, void *, bool &);
 
2813
template void * BackupRestore::convert_array< Hvarbinary, Hvarbinary >(const void *, void *, bool &);
 
2814
template void * BackupRestore::convert_array< Hvarbinary, Hlongvarbinary >(const void *, void *, bool &);
 
2815
template void * BackupRestore::convert_array< Hlongvarbinary, Hbinary >(const void *, void *, bool &);
 
2816
template void * BackupRestore::convert_array< Hlongvarbinary, Hvarbinary >(const void *, void *, bool &);
 
2817
template void * BackupRestore::convert_array< Hlongvarbinary, Hlongvarbinary >(const void *, void *, bool &);
 
2818
 
 
2819
// integral promotions
 
2820
template void * BackupRestore::convert_integral<Hint8, Hint16>(const void *, void *, bool &);
 
2821
template void * BackupRestore::convert_integral<Hint8, Hint24>(const void *, void *, bool &);
 
2822
template void * BackupRestore::convert_integral<Hint8, Hint32>(const void *, void *, bool &);
 
2823
template void * BackupRestore::convert_integral<Hint8, Hint64>(const void *, void *, bool &);
 
2824
template void * BackupRestore::convert_integral<Hint16, Hint24>(const void *, void *, bool &);
 
2825
template void * BackupRestore::convert_integral<Hint16, Hint32>(const void *, void *, bool &);
 
2826
template void * BackupRestore::convert_integral<Hint16, Hint64>(const void *, void *, bool &);
 
2827
template void * BackupRestore::convert_integral<Hint24, Hint32>(const void *, void *, bool &);
 
2828
template void * BackupRestore::convert_integral<Hint24, Hint64>(const void *, void *, bool &);
 
2829
template void * BackupRestore::convert_integral<Hint32, Hint64>(const void *, void *, bool &);
 
2830
template void * BackupRestore::convert_integral<Huint8, Huint16>(const void *, void *, bool &);
 
2831
template void * BackupRestore::convert_integral<Huint8, Huint24>(const void *, void *, bool &);
 
2832
template void * BackupRestore::convert_integral<Huint8, Huint32>(const void *, void *, bool &);
 
2833
template void * BackupRestore::convert_integral<Huint8, Huint64>(const void *, void *, bool &);
 
2834
template void * BackupRestore::convert_integral<Huint16, Huint24>(const void *, void *, bool &);
 
2835
template void * BackupRestore::convert_integral<Huint16, Huint32>(const void *, void *, bool &);
 
2836
template void * BackupRestore::convert_integral<Huint16, Huint64>(const void *, void *, bool &);
 
2837
template void * BackupRestore::convert_integral<Huint24, Huint32>(const void *, void *, bool &);
 
2838
template void * BackupRestore::convert_integral<Huint24, Huint64>(const void *, void *, bool &);
 
2839
template void * BackupRestore::convert_integral<Huint32, Huint64>(const void *, void *, bool &);
 
2840
 
 
2841
// integral demotions
 
2842
template void * BackupRestore::convert_integral<Hint16, Hint8>(const void *, void *, bool &);
 
2843
template void * BackupRestore::convert_integral<Hint24, Hint8>(const void *, void *, bool &);
 
2844
template void * BackupRestore::convert_integral<Hint24, Hint16>(const void *, void *, bool &);
 
2845
template void * BackupRestore::convert_integral<Hint32, Hint8>(const void *, void *, bool &);
 
2846
template void * BackupRestore::convert_integral<Hint32, Hint16>(const void *, void *, bool &);
 
2847
template void * BackupRestore::convert_integral<Hint32, Hint24>(const void *, void *, bool &);
 
2848
template void * BackupRestore::convert_integral<Hint64, Hint8>(const void *, void *, bool &);
 
2849
template void * BackupRestore::convert_integral<Hint64, Hint16>(const void *, void *, bool &);
 
2850
template void * BackupRestore::convert_integral<Hint64, Hint24>(const void *, void *, bool &);
 
2851
template void * BackupRestore::convert_integral<Hint64, Hint32>(const void *, void *, bool &);
 
2852
template void * BackupRestore::convert_integral<Huint16, Huint8>(const void *, void *, bool &);
 
2853
template void * BackupRestore::convert_integral<Huint24, Huint8>(const void *, void *, bool &);
 
2854
template void * BackupRestore::convert_integral<Huint24, Huint16>(const void *, void *, bool &);
 
2855
template void * BackupRestore::convert_integral<Huint32, Huint8>(const void *, void *, bool &);
 
2856
template void * BackupRestore::convert_integral<Huint32, Huint16>(const void *, void *, bool &);
 
2857
template void * BackupRestore::convert_integral<Huint32, Huint24>(const void *, void *, bool &);
 
2858
template void * BackupRestore::convert_integral<Huint64, Huint8>(const void *, void *, bool &);
 
2859
template void * BackupRestore::convert_integral<Huint64, Huint16>(const void *, void *, bool &);
 
2860
template void * BackupRestore::convert_integral<Huint64, Huint24>(const void *, void *, bool &);
 
2861
template void * BackupRestore::convert_integral<Huint64, Huint32>(const void *, void *, bool &);
 
2862
 
 
2863
// integral signedness BackupRestore::conversions
 
2864
template void * BackupRestore::convert_integral<Hint8, Huint8>(const void *, void *, bool &);
 
2865
template void * BackupRestore::convert_integral<Hint16, Huint16>(const void *, void *, bool &);
 
2866
template void * BackupRestore::convert_integral<Hint24, Huint24>(const void *, void *, bool &);
 
2867
template void * BackupRestore::convert_integral<Hint32, Huint32>(const void *, void *, bool &);
 
2868
template void * BackupRestore::convert_integral<Hint64, Huint64>(const void *, void *, bool &);
 
2869
template void * BackupRestore::convert_integral<Huint8, Hint8>(const void *, void *, bool &);
 
2870
template void * BackupRestore::convert_integral<Huint16, Hint16>(const void *, void *, bool &);
 
2871
template void * BackupRestore::convert_integral<Huint24, Hint24>(const void *, void *, bool &);
 
2872
template void * BackupRestore::convert_integral<Huint32, Hint32>(const void *, void *, bool &);
 
2873
template void * BackupRestore::convert_integral<Huint64, Hint64>(const void *, void *, bool &);
 
2874
 
 
2875
// integral signedness+promotion BackupRestore::conversions
 
2876
template void * BackupRestore::convert_integral<Hint8, Huint16>(const void *, void *, bool &);
 
2877
template void * BackupRestore::convert_integral<Hint8, Huint24>(const void *, void *, bool &);
 
2878
template void * BackupRestore::convert_integral<Hint8, Huint32>(const void *, void *, bool &);
 
2879
template void * BackupRestore::convert_integral<Hint8, Huint64>(const void *, void *, bool &);
 
2880
template void * BackupRestore::convert_integral<Hint16, Huint24>(const void *, void *, bool &);
 
2881
template void * BackupRestore::convert_integral<Hint16, Huint32>(const void *, void *, bool &);
 
2882
template void * BackupRestore::convert_integral<Hint16, Huint64>(const void *, void *, bool &);
 
2883
template void * BackupRestore::convert_integral<Hint24, Huint32>(const void *, void *, bool &);
 
2884
template void * BackupRestore::convert_integral<Hint24, Huint64>(const void *, void *, bool &);
 
2885
template void * BackupRestore::convert_integral<Hint32, Huint64>(const void *, void *, bool &);
 
2886
template void * BackupRestore::convert_integral<Huint8, Hint16>(const void *, void *, bool &);
 
2887
template void * BackupRestore::convert_integral<Huint8, Hint24>(const void *, void *, bool &);
 
2888
template void * BackupRestore::convert_integral<Huint8, Hint32>(const void *, void *, bool &);
 
2889
template void * BackupRestore::convert_integral<Huint8, Hint64>(const void *, void *, bool &);
 
2890
template void * BackupRestore::convert_integral<Huint16, Hint24>(const void *, void *, bool &);
 
2891
template void * BackupRestore::convert_integral<Huint16, Hint32>(const void *, void *, bool &);
 
2892
template void * BackupRestore::convert_integral<Huint16, Hint64>(const void *, void *, bool &);
 
2893
template void * BackupRestore::convert_integral<Huint24, Hint32>(const void *, void *, bool &);
 
2894
template void * BackupRestore::convert_integral<Huint24, Hint64>(const void *, void *, bool &);
 
2895
template void * BackupRestore::convert_integral<Huint32, Hint64>(const void *, void *, bool &);
 
2896
 
 
2897
// integral signedness+demotion BackupRestore::conversions
 
2898
template void * BackupRestore::convert_integral<Hint16, Huint8>(const void *, void *, bool &);
 
2899
template void * BackupRestore::convert_integral<Hint24, Huint8>(const void *, void *, bool &);
 
2900
template void * BackupRestore::convert_integral<Hint24, Huint16>(const void *, void *, bool &);
 
2901
template void * BackupRestore::convert_integral<Hint32, Huint8>(const void *, void *, bool &);
 
2902
template void * BackupRestore::convert_integral<Hint32, Huint16>(const void *, void *, bool &);
 
2903
template void * BackupRestore::convert_integral<Hint32, Huint24>(const void *, void *, bool &);
 
2904
template void * BackupRestore::convert_integral<Hint64, Huint8>(const void *, void *, bool &);
 
2905
template void * BackupRestore::convert_integral<Hint64, Huint16>(const void *, void *, bool &);
 
2906
template void * BackupRestore::convert_integral<Hint64, Huint24>(const void *, void *, bool &);
 
2907
template void * BackupRestore::convert_integral<Hint64, Huint32>(const void *, void *, bool &);
 
2908
template void * BackupRestore::convert_integral<Huint16, Hint8>(const void *, void *, bool &);
 
2909
template void * BackupRestore::convert_integral<Huint24, Hint8>(const void *, void *, bool &);
 
2910
template void * BackupRestore::convert_integral<Huint24, Hint16>(const void *, void *, bool &);
 
2911
template void * BackupRestore::convert_integral<Huint32, Hint8>(const void *, void *, bool &);
 
2912
template void * BackupRestore::convert_integral<Huint32, Hint16>(const void *, void *, bool &);
 
2913
template void * BackupRestore::convert_integral<Huint32, Hint24>(const void *, void *, bool &);
 
2914
template void * BackupRestore::convert_integral<Huint64, Hint8>(const void *, void *, bool &);
 
2915
template void * BackupRestore::convert_integral<Huint64, Hint16>(const void *, void *, bool &);
 
2916
template void * BackupRestore::convert_integral<Huint64, Hint24>(const void *, void *, bool &);
 
2917
template void * BackupRestore::convert_integral<Huint64, Hint32>(const void *, void *, bool &);