MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
consumer_restore.cpp
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 
560 static
561 bool
562 dissect_table_name(const char * qualified_table_name,
563  BaseString & db_name,
564  BaseString & schema_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 
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 
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 &&
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){
998  {
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  {
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  }
1040  {
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  {
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  {
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  {
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 
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
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 &&
1214  {
1215  if (ndbtab->getNoOfColumns() == 2)
1216  {
1217  apply_table_format= 1;
1218  }
1219  else if
1220  (ndbtab->getColumn(2)->getType() == NdbDictionary::Column::Varchar &&
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 
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 
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
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  }
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 
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 
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
1784  if (!m_restore && !m_restore_meta && !m_rebuild_indexes && !m_disable_indexes)
1785  return true;
1786 
1787  const char * name = table.getTableName();
1788 
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 
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  {
1900 
1901  if (t == NdbDictionary::Column::Varchar ||
1903  tableImpl.getColumn(i)->setArrayType(NdbDictionary::Column::ArrayTypeShortVar);
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);
1960  if (t == NdbDictionary::Column::Blob ||
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  {
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  {
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 
2113 {
2114  Uint32 partition_id = cb->fragId;
2115  Uint32 n_bytes;
2116  while (cb->retries < 10)
2117  {
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()){
2204  length = src[0] + 1;
2205  break;
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;
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 
2346 {
2347  m_transactions--;
2348 
2349  if (result < 0)
2350  {
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  {
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 
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 
2408  err << "Temporary error: " << error << endl;
2409  m_temp_error = true;
2410  NdbSleep_MilliSleep(sleepTime);
2411  return true;
2412  // RETRY
2413 
2415  err << "Unknown: " << error << endl;
2416  return false;
2417  // ERROR!
2418 
2419  default:
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 &&
2648  ok= true;
2649  break;
2650  case LogEntry::LE_UPDATE:
2651  case LogEntry::LE_DELETE:
2652  if(errobj.status == NdbError::PermanentError &&
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*>;
2791 template class Vector<NdbDictionary::Tablespace*>;
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 &);