200 lines
6.4 KiB
C++
200 lines
6.4 KiB
C++
/* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License, version 2.0,
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is also distributed with certain software (including
|
|
but not limited to OpenSSL) that is licensed under separate terms,
|
|
as designated in a particular file or component or in included license
|
|
documentation. The authors of MySQL hereby grant you an additional
|
|
permission to link the program and your derivative works with the
|
|
separately licensed software that they have included with MySQL.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License, version 2.0, for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
#include <NdbDictionary.hpp>
|
|
|
|
#include "my_compiler.h"
|
|
|
|
/*
|
|
* Move data between "compatible" tables.
|
|
*
|
|
* Uses batches of insert-into-target / delete-from-source.
|
|
* Compared to copying alter table, the advantages are
|
|
* 1) does not need double storage 2) can be restarted
|
|
* after temporary failure.
|
|
*
|
|
* Use init() to define source / target and then move_data().
|
|
* Methods return -1 on error and 0 on success. On temporary
|
|
* error call move_data() again to continue.
|
|
*
|
|
* Use get_error() for details. Negative error code means
|
|
* non-recoverable error. Positive error code is ndb error
|
|
* which may be temporary.
|
|
*
|
|
* Like ndb_restore, remaps columns based on name.
|
|
*
|
|
* Used from ndb_restore for char<->text conversion. Here
|
|
* user pre-creates the new table and then loads data into it
|
|
* via ndb_restore -r. This first loads data into a temporary
|
|
* "staging table" which has same structure as table in backup.
|
|
* Then move_data() is called to move data into the new table.
|
|
*
|
|
* Current version handles data conversions between all char,
|
|
* binary, text, blob types.
|
|
*
|
|
* The conversion methods should be unified with ndb_restore.
|
|
* Missing cases (date and numeric types) should be added.
|
|
*/
|
|
|
|
struct Ndb_move_data {
|
|
struct Opts {
|
|
enum {
|
|
MD_ABORT_ON_ERROR = 0x1,
|
|
MD_EXCLUDE_MISSING_COLUMNS = 0x2,
|
|
MD_ATTRIBUTE_PROMOTION = 0x4,
|
|
MD_ATTRIBUTE_DEMOTION = 0x8
|
|
};
|
|
int flags;
|
|
// for parsing --staging-tries (but caller handles retries)
|
|
struct Tries {
|
|
int maxtries; // 0 = no limit
|
|
int mindelay;
|
|
int maxdelay;
|
|
Tries() : maxtries(0), mindelay(1000), maxdelay(60*1000) {}
|
|
};
|
|
Opts();
|
|
};
|
|
struct Stat {
|
|
Uint64 rows_moved; // in current move_data() call
|
|
Uint64 rows_total; // total moved so far
|
|
Uint64 truncated; // truncated attributes so far
|
|
Stat();
|
|
};
|
|
struct Error {
|
|
enum {
|
|
InvalidState = -101,
|
|
InvalidSource = -102,
|
|
InvalidTarget = -103,
|
|
UnsupportedConversion = -201,
|
|
NoExcludeMissingFlag = -202,
|
|
NoPromotionFlag = -203,
|
|
NoDemotionFlag = -204,
|
|
DataTruncated = -301
|
|
};
|
|
int line;
|
|
int code;
|
|
char message[512];
|
|
NdbError ndberror; // valid if code > 0
|
|
bool is_temporary() const;
|
|
Error();
|
|
};
|
|
Ndb_move_data();
|
|
~Ndb_move_data();
|
|
int init(const NdbDictionary::Table* source,
|
|
const NdbDictionary::Table* target);
|
|
void set_opts_flags(int flags);
|
|
static void unparse_opts_tries(char* opt, const Opts::Tries& ot);
|
|
static int parse_opts_tries(const char* opt, Opts::Tries& retry);
|
|
int move_data(Ndb* ndb);
|
|
void error_insert(); // insert random temporary error
|
|
const Stat& get_stat();
|
|
const Error& get_error();
|
|
|
|
private:
|
|
const NdbDictionary::Table* m_source; // source rows moved from
|
|
const NdbDictionary::Table* m_target; // target rows moved to
|
|
struct Attr {
|
|
enum {
|
|
TypeNone = 0,
|
|
TypeArray,
|
|
TypeBlob,
|
|
TypeOther
|
|
};
|
|
const NdbDictionary::Column* column;
|
|
const char* name;
|
|
int id; // own id (array index)
|
|
int map_id; // column id in other table
|
|
int type;
|
|
Uint32 size_in_bytes;
|
|
Uint32 length_bytes;
|
|
Uint32 data_size; // size_in_bytes - length_bytes
|
|
Uint32 tiny_bytes;
|
|
int pad_char;
|
|
bool equal; // attr1,attr2 equal non-blobs
|
|
Attr();
|
|
};
|
|
Attr* m_sourceattr;
|
|
Attr* m_targetattr;
|
|
void set_type(Attr& attr, const NdbDictionary::Column* c);
|
|
Uint32 calc_str_len_truncated(CHARSET_INFO *cs, const char *data, uint32 maxlen);
|
|
int check_nopk(const Attr& attr1, const Attr& attr2);
|
|
int check_promotion(const Attr& attr1, const Attr& attr2);
|
|
int check_demotion(const Attr& attr1, const Attr& attr2);
|
|
int check_sizes(const Attr& attr1, const Attr& attr2);
|
|
int check_unsupported(const Attr& attr1, const Attr& attr2);
|
|
int check_tables();
|
|
struct Data {
|
|
char* data;
|
|
Data* next;
|
|
Data();
|
|
~Data();
|
|
};
|
|
Data* m_data; // blob data for the batch, used for blob2blob
|
|
char* alloc_data(Uint32 n);
|
|
void release_data();
|
|
struct Op {
|
|
Ndb* ndb;
|
|
NdbTransaction* scantrans;
|
|
NdbScanOperation* scanop;
|
|
NdbTransaction* updatetrans;
|
|
NdbOperation* updateop;
|
|
union Value {
|
|
NdbRecAttr* ra;
|
|
NdbBlob* bh;
|
|
};
|
|
Value* values;
|
|
int buflen;
|
|
char* buf1;
|
|
char* buf2;
|
|
Uint32 rows_in_batch;
|
|
Uint32 truncated_in_batch;
|
|
bool end_of_scan;
|
|
Op();
|
|
~Op();
|
|
};
|
|
Op m_op;
|
|
int start_scan();
|
|
int copy_other_to_other(const Attr& attr1, const Attr& attr2);
|
|
int copy_data_to_array(const char* data1, const Attr& attr2,
|
|
Uint32 length1, Uint32 length1x);
|
|
int copy_array_to_array(const Attr& attr1, const Attr& attr2);
|
|
int copy_array_to_blob(const Attr& attr1, const Attr& attr2);
|
|
int copy_blob_to_array(const Attr& attr1, const Attr& attr2);
|
|
int copy_blob_to_blob(const Attr& attr1, const Attr& attr2);
|
|
int copy_attr(const Attr& attr1, const Attr& attr2);
|
|
int move_row();
|
|
int move_batch();
|
|
void close_op(Ndb* ndb, int ret);
|
|
Opts m_opts;
|
|
Stat m_stat;
|
|
Error m_error;
|
|
void set_error_line(int line);
|
|
void set_error_code(int code, const char* fmt, ...)
|
|
MY_ATTRIBUTE((format(printf, 3, 4)));
|
|
void set_error_code(const NdbError& ndberror);
|
|
void reset_error();
|
|
friend class NdbOut& operator<<(NdbOut&, const Error&);
|
|
bool m_error_insert;
|
|
void invoke_error_insert();
|
|
void abort_on_error();
|
|
};
|