DCL 4.0
Loading...
Searching...
No Matches
EntityCopy.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#if __DCL_WINDOWS
4#include <windows.h>
5#endif
6
7#include <dcl/DateTime.h>
8
9#include "main.h"
10#include "EntityCopy.h"
11
12#define __TRACE_THIS 0
13#if __TRACE_THIS
14#define __DCL_TRACE0_N __DCL_TRACE0
15#define __DCL_TRACE1_N __DCL_TRACE1
16#define __DCL_TRACE2_N __DCL_TRACE2
17#define __DCL_TRACE3_N __DCL_TRACE3
18#define __DCL_TRACE4_N __DCL_TRACE4
19#else
20#define __DCL_TRACE0_N(fmt, arg)
21#define __DCL_TRACE1_N(fmt, arg)
22#define __DCL_TRACE2_N(fmt, arg1, arg2)
23#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
24#define __DCL_TRACE4_N(fmt, arg1, arg2, arg3, arg4)
25#endif
26
27__DCL_BEGIN_NAMESPACE
28
29#if __DCL_DEBUG
30#undef __THIS_FILE__
31static const char_t __THIS_FILE__[] = __T("entitycopy/EntityCopy.cpp");
32#endif
33
34static DatabaseHelper __database_helper__[] = {
35 {
36 L"DCLFirebird",
37 L"SELECT RDB$RELATION_NAME FROM RDB$RELATIONS"
38 " WHERE RDB$SYSTEM_FLAG = 0 AND RDB$RELATION_TYPE = 0"
39 " ORDER BY RDB$RELATION_NAME",
40 L"DELETE FROM "
41 },
42 {
43 L"DCLInterBase",
44 L"SELECT RDB$RELATION_NAME FROM RDB$RELATIONS"
45 " WHERE RDB$SYSTEM_FLAG = 0 AND RDB$RELATION_TYPE = 'PERSISTENT'"
46 " ORDER BY RDB$RELATION_NAME",
47 L"DELETE FROM "
48 },
49 {
50 L"DCLInformix",
51 L"SELECT TABNAME FROM SYSTABLES"
52 " WHERE OWNER = CURRENT_USER AND TABTYPE = 'T'"
53 " ORDER BY TABNAME",
54 L"TRUNCATE TABLE "
55 },
56 {
57 L"DCLMariaDB",
58 L"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"
59 " WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA = DATABASE()"
60 " ORDER BY TABLE_NAME",
61 L"TRUNCATE TABLE "
62 },
63 {
64 L"DCLOracleDb",
65 L"SELECT TABLE_NAME FROM USER_TABLES"
66 " ORDER BY TABLE_NAME",
67 L"TRUNCATE TABLE "
68 },
69 {
70 L"DCLPostgreSQL",
71 L"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"
72 " WHERE TABLE_TYPE = 'BASE TABLE'"
73 " AND TABLE_SCHEMA NOT In('pg_catalog', 'information_schema')"
74 " ORDER by TABLE_NAME",
75 L"TRUNCATE TABLE "
76 },
77 { NULL, NULL, NULL }
78};
79
80static const DatabaseHelper* __get_helper(const String& _driverName)
81{
82 const DatabaseHelper* r = __database_helper__;
83 while (r->driverName) {
84 if (_driverName == r->driverName) {
85 break;
86 }
87 r++;
88 }
89 return r;
90}
91
93{
94 name = _s.name;
95 columns = _s.columns;
96 toName = _s.toName;
98}
99
101{
102 name = _s.name;
103 columns = _s.columns;
104 toName = _s.toName;
105 toColumns = _s.toColumns;
106
107 return *this;
108}
109
111{
112 return String::format(L"name[%ls] columns[%ls] toName[%ls] toColumns[%ls",
113 name.data(), columns.data(), toName.data(), toColumns.data()
114 );
115}
116
118 const String& _srcDriver, const String& _dstDriver)
119 : __args(_args), __srcConn(_srcDriver), __dstConn(_dstDriver)
121{
122 __srcHelper = __get_helper(_srcDriver);
123 __dstHelper = __get_helper(_dstDriver);
124
126 __DCL_TRACE2_N(L"helper[%ls][%ls]\n", __srcHelper->driverName, __dstHelper->driverName);
127
128 __lineRuler.assign(L'-', 80);
129 __lineIndent.assign(L' ', 4);
130}
131
132static void __get_name_columns(const String& _entity, String& _name, String& _columns)
133{
134 size_t index = _entity.indexOf(L'(');
135 if (index != (size_t)-1) {
136 _name = _entity.substring(0, index);
137 _columns = _entity.substring(index).trim().trim(L"()").trim();
138 }
139 else {
140 _name = _entity;
141 }
142}
143
144static void __verbose_out(Writer& _output,
145 const String& _sql, const String& _indent)
146{
147 const wchar_t* begin = _sql.data();
148 const wchar_t* end = begin + _sql.length();
149 const wchar_t* p = begin;
150 while (p < end) {
151 // 길이가 70 이상이고, ' ', ',' 이전까지의 문자열을 출력한다.
152 p += 70;
153 while (p < end) {
154 if (*p == L' ' || *p == L',') {
155 break;
156 }
157 p++;
158 }
159 if (p < end) {
160 _output << _indent;
161 if (begin > _sql.data()) {
162 _output << _indent;
163 }
164 _output.write(begin, p - begin);
165 _output << endl;
166 if (*p == L' ') {
167 p++;
168 }
169 begin = p;
170 }
171 }
172 if (begin < end) {
173 _output << _indent;
174 if (begin > _sql.data()) {
175 _output << _indent;
176 }
177 _output.write(begin, end - begin);
178 _output << endl;
179 }
180}
181
184{
185 try {
186 __srcConn.open(__args.source());
187 __args.output() << L"Source database connected. ["
188 << __args.source() << L"]" << endl;
189
190 __dstConn.open(__args.destination());
191 __args.output() << L"Destination database connected. ["
192 << __args.destination() << L"]" << endl;
193 }
194 catch (Exception* _e) {
195 __args.output() << L"Database connection failed. ["
196 << _e->toStringAll() << L"]" << endl;
197 _e->destroy();
198 return false;
199 }
200
201 if (!__args.entities().isEmpty()) {
202 StringArray a;
203 __args.entities().split(L';', a);
204 for (size_t i = 0; i < a.size(); i++) {
205 const String& s = a[i];
206 Entity e;
207 if (s.contains(L'=')) {
208 StringArray pair;
209 s.split(L'=', pair);
210 __get_name_columns(pair[0], e.name, e.columns);
211 __get_name_columns(pair[1], e.toName, e.toColumns);
212 }
213 else {
214 __get_name_columns(s, e.name, e.columns);
215 }
216 __entities.add(e);
217 __DCL_TRACE1_N(L"entity[%ls]\n", e.toString().data());
218 }
219 }
220 else {
221 Array<Entity> srcEntities;
222 Array<Entity> dstEntities;
223
224 String srcTableSQL = __srcHelper->selectTableList;
225 String dstTableSQL = __dstHelper->selectTableList;
226
227 if (__args.verbose()) {
228 __args.output() << L"Source entities SQL" << endl;
229 __verbose_out(__args.output(), srcTableSQL, __lineIndent);
230 __args.output() << L"Destination entities SQL" << endl;
231 __verbose_out(__args.output(), dstTableSQL, __lineIndent);
232 }
233
234 {
235 __srcConn.startTrans();
236 SQLQuery q(__srcConn);
237 q.execute(srcTableSQL);
238 q.fetch();
239 while (!q.eof()) {
240 Entity e;
241 e.name = q.fields()[0].asString().trim();
242 srcEntities.add(e);
243 q.fetch();
244 }
245 __srcConn.commitTrans();
246 }
247
248 {
249 __dstConn.startTrans();
250 SQLQuery q(__dstConn);
251 q.execute(dstTableSQL);
252 q.fetch();
253 while (!q.eof()) {
254 Entity e;
255 e.name = q.fields()[0].asString().trim();
256 dstEntities.add(e);
257 q.fetch();
258 }
259 __dstConn.commitTrans();
260 }
261
262 if (srcEntities.size() < dstEntities.size()) {
263 __entities = srcEntities;
264 }
265 else {
266 __entities = dstEntities;
267 }
268#if __TRACE_THIS
269 StringBuilder sb = L"{";
270 for (size_t i = 0; i < __entities.size(); i++) {
271 if (i > 0) {
272 sb.append(L", ");
273 }
274 sb.append(__entities[i].name);
275 }
276 sb.append(L"}");
277 __DCL_TRACE2_N(L"__entities[%ls][%ls]\n",
278 srcEntities.size() < dstEntities.size() ? L"src" : L"dst",
279 sb.toString().data());
280#endif
281 }
282 return __entities.size() > 0;
283}
284
287{
288 switch (_field.dataType()) {
289 case SQL::typeInteger: {
290 if (_field.dataSizeMax() <= sizeof(int32_t)) {
291 int32_t value = 0;
292 _field.getValue(value);
293 _param.setValue(value);
294 }
295 else {
296 int64_t value = 0;
297 _field.getValue(value);
298 _param.setValue(value);
299 }
300 break;
301 }
302 case SQL::typeUInteger: {
303 if (_field.dataSizeMax() <= sizeof(uint32_t)) {
304 uint32_t value = 0;
305 _field.getValue(value);
306 _param.setValue(value);
307 }
308 else {
309 uint64_t value = 0;
310 _field.getValue(value);
311 _param.setValue(value);
312 }
313 break;
314 }
315 case SQL::typeFloat: {
316 if (_field.dataSizeMax() == sizeof(float)) {
317 float value = 0.;
318 _field.getValue(value);
319 _param.setValue(value);
320 }
321 else {
322 double value = 0.;
323 _field.getValue(value);
324 _param.setValue(value);
325 }
326 break;
327 }
328 case SQL::typeNumeric: {
329 if (_field.precision() > 0 && _field.scale() == 0) {
330 // 12345678901234567890
331 // 2147483647
332 // 9223372036854775807
333 if (_field.precision() <= __args.i4precision()) {
334 int32_t value = 0;
335 _field.getValue(value);
336 _param.setValue(value);
337 break;
338 }
339 else if (_field.precision() <= __args.i8precision()) {
340 int64_t value = 0;
341 _field.getValue(value);
342 _param.setValue(value);
343 break;
344 }
345 else {
346 // BigInteger
347 }
348 }
349 ByteString value;
350 _field.getValue(value, SQL::typeText);
351 _param.setValue(value, SQL::typeText);
352 break;
353 }
354 case SQL::typeDate: {
355 SQL::Date value;
356 _field.getValue(value);
357 _param.setData(&value, sizeof(value),
359 break;
360 }
361 case SQL::typeTime: {
362 SQL::Time value;
363 _field.getValue(value);
364 _param.setData(&value, sizeof(value),
366 break;
367 }
370 SQL::TimeStamp value;
371 _field.getValue(value);
372 _param.setData(&value, sizeof(value),
373 _field.dataType(), SQL::typeTimeStamp);
374 break;
375 }
378 case SQL::typeIntervalDs: {
379 SQL::Interval value;
380 _field.getValue(value);
381 _param.setData(&value, sizeof(value),
382 _field.dataType(), SQL::typeInterval);
383 break;
384 }
385 case SQL::typeText:
387 case SQL::typeClob: {
388 ByteString value;
389 _field.getValue(value, SQL::typeText);
390 _param.setValue(value, SQL::typeText);
391 break;
392 }
393 case SQL::typeBinary:
395 case SQL::typeBlob: {
396 ByteString value;
397 _field.getValue(value, SQL::typeBinary);
398 _param.setValue(value, SQL::typeBinary);
399 break;
400 }
401 }
402}
403
406{
408 __args.output() << __lineRuler << endl
409 << _e.name << L" [" << begin.toString()
410 << L"]" << endl;
411
412 __srcConn.startTrans();
413 String selectSQL = getSelectSQL(_e);
414 SQLQuery select(__srcConn);
415 select.execute(selectSQL);
416
417 String insertSQL = getInsertSQL(_e, select.fields());
418 String truncateSQL = getTruncateSQL(_e);
419
420 if (__args.truncate()) {
421 if (__args.verbose()) {
422 __args.output() << __lineIndent << truncateSQL << endl;
423 }
424 if (!__args.dryrun()) {
425 __dstConn.startTrans();
426 __dstConn.execute(truncateSQL);
427 __dstConn.commitTrans();
428 }
429 }
430
431 if (__args.verbose()) {
432 __verbose_out(__args.output(), selectSQL, __lineIndent);
433 __verbose_out(__args.output(), insertSQL, __lineIndent);
434 }
435
436 __dstConn.startTrans();
437
438 SQLQuery insert(__dstConn);
439 insert.prepare(insertSQL);
440
441 __DCL_ASSERT(select.fields().count() == insert.params().count());
442
443 select.fetch();
444 int rows = 0;
445 while (!select.eof()) {
446 rows++;
447
448 for (size_t i = 0; i < select.fields().count(); i++) {
449 SQLField& field = select.fields()[i];
450 SQLParam& param = insert.params()[i];
451 if (field.isNull()) {
452 param.setNull();
453 }
454 else {
455 try {
456 translateFieldValue(field, param);
457 }
458 catch (Exception* e) {
459 __DCL_TRACE4(L"%ls[%d][%ls] [%ls]\n", _e.name.data(), rows,
460 field.name().data(), e->toStringAll().data());
461 throw e;
462 }
463 }
464 }
465
466 if (!__args.dryrun()) {
467 insert.execute();
468 //__DCL_TRACE1_N(L"affectedRows[%zd]\n", insert.affectedRows());
469 if (__args.rows() > 0 && (rows % __args.rows()) == 0) {
470 __dstConn.commitTrans();
471 __dstConn.startTrans();
472 insert.prepare(insertSQL);
473 if (__args.verbose()) {
474 __args.output() << __lineIndent << L"COMMIT " << rows << endl;
475 }
476 }
477 }
478 select.fetch();
479 }
480
481 __dstConn.commitTrans();
482 __srcConn.commitTrans();
483
485 __args.output() << _e.name
486 << L" [" << rows << L" rows transfered. " << (end - begin).toString()
487 << L"]" << endl;
488}
489
491{
492 for (size_t i = 0; i < __entities.size(); i++) {
494 }
495}
496
498{
499 StringBuilder sb = L"SELECT ";
500 sb.append(!_e.columns.isEmpty() ? _e.columns : L"*")
501 .append(L" FROM ")
502 .append(_e.name);
503
504 return sb;
505}
506
507String EntityCopy::getInsertSQL(const Entity& _e, const SQLFields& _fields)
508{
509 StringBuilder sb = L"INSERT INTO ";
510 sb.append(!_e.toName.isEmpty() ? _e.toName : _e.name)
511 .append(L"(");
512 if (!_e.toColumns.isEmpty()) {
513 sb.append(_e.toColumns);
514 }
515 else if (!_e.columns.isEmpty()) {
516 sb.append(_e.columns);
517 }
518 else {
519 sb.append(_fields[0].name());
520 for (size_t i = 1; i < _fields.count(); i++) {
521 sb.append(L",").append(_fields[i].name());
522 }
523 }
524 sb.append(L") VALUES (?");
525
526 for (size_t i = 1; i < _fields.count(); i++) {
527 sb.append(L",?");
528 }
529 sb.append(L")");
530
531 return sb;
532}
533
535{
536 StringBuilder sb = __dstHelper->truncateTable;
537 sb.append(!_e.toName.isEmpty() ? _e.toName : _e.name);
538 return sb;
539}
540
541__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
wchar_t char_t
Definition Config.h:275
#define __DCL_THROWS2(e1, e2)
Definition Config.h:168
#define __DCL_THROWS1(e)
Definition Config.h:167
#define __DCL_TRACE2_N(fmt, arg1, arg2)
#define __DCL_TRACE2_N(fmt, arg1, arg2)
#define __DCL_ASSERT(expr)
Definition Object.h:371
#define __DCL_TRACE4(fmt, arg1, arg2, arg3, arg4)
Definition Object.h:379
#define __T(str)
Definition Object.h:44
#define endl
ByteString r
Definition ArrayT.h:42
size_t size() const
Definition ArrayT.h:197
Array< ELEMENT > & add(const ELEMENT &_element)
Definition ArrayT.h:144
String toString() const
Definition DateTime.cpp:826
static DateTime getCurrentLocalTime()
Definition DateTime.cpp:937
String getInsertSQL(const Entity &_e, const SQLFields &_fields)
void copyEntity(const Entity &_e) __DCL_THROWS1(SQLException *)
EntityCopy(const MainArguments &_args, const String &_srcDriver, const String &_dstDriver) __DCL_THROWS1(SQLDriverException *)
const MainArguments & __args
Definition EntityCopy.h:51
SQLConnection __dstConn
Definition EntityCopy.h:53
const DatabaseHelper * __srcHelper
Definition EntityCopy.h:55
String getTruncateSQL(const Entity &_e)
bool initialize() __DCL_THROWS1(SQLException *)
Array< Entity > __entities
Definition EntityCopy.h:58
String __lineIndent
Definition EntityCopy.h:71
void translateFieldValue(SQLField &_field, SQLParam &_param) __DCL_THROWS1(SQLException *)
SQLConnection __srcConn
Definition EntityCopy.h:52
const DatabaseHelper * __dstHelper
Definition EntityCopy.h:56
String getSelectSQL(const Entity &_e)
String __lineRuler
Definition EntityCopy.h:70
virtual void destroy()
Definition Exception.cpp:74
String toStringAll() const
Definition Exception.cpp:45
Definition SQL.h:48
size_t count() const
Definition SQL.inl:93
@ typeBinary
Definition SQLCore.h:76
@ typeClob
Definition SQLCore.h:79
@ typeNumeric
Definition SQLCore.h:67
@ typeTime
Definition SQLCore.h:69
@ typeLongBinary
Definition SQLCore.h:78
@ typeUInteger
Definition SQLCore.h:65
@ typeTimeStamp
Definition SQLCore.h:70
@ typeBlob
Definition SQLCore.h:80
@ typeTimeStampTz
Definition SQLCore.h:71
@ typeInterval
Definition SQLCore.h:72
@ typeIntervalDs
Definition SQLCore.h:74
@ typeDate
Definition SQLCore.h:68
@ typeText
Definition SQLCore.h:75
@ typeFloat
Definition SQLCore.h:66
@ typeInteger
Definition SQLCore.h:64
@ typeIntervalYm
Definition SQLCore.h:73
@ typeLongText
Definition SQLCore.h:77
size_t count() const
Definition SQL.inl:118
_CONST SQLParams & params() _CONST
Definition SQL.inl:144
void prepare(const String &_sql) __DCL_THROWS2(SQLException *
_CONST SQLFields & fields() _CONST
Definition SQL.inl:139
void CharsetConvertException *void execute() __DCL_THROWS1(SQLException *)
Definition SQLQuery.cpp:307
bool eof() const
Definition SQL.inl:129
void CharsetConvertException *void fetch() __DCL_THROWS1(SQLException *)
Definition SQLQuery.cpp:329
Entity & operator=(const Entity &_s)
String toName
Definition EntityCopy.h:29
String toColumns
Definition EntityCopy.h:30
String name
Definition EntityCopy.h:27
String toString()
String columns
Definition EntityCopy.h:28