DCL 3.7.4
Loading...
Searching...
No Matches
EntityCopy.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#ifdef __WINNT__
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_HAVE_THIS_FILE__
30#undef __THIS_FILE__
31static const char_t __THIS_FILE__[] = __T("entitycopy/EntityCopy.cpp");
32#endif
33
34static DatabaseHelper __database_helper__[] = {
35 {
36 L"Firebird", // LI-V6.3.2.1613 Firebird 5.0
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"InterBase", // InterBase LI-V6.3.2.1613
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"Informix", // IBM Informix Dynamic Server
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"MariaDB", // 11.8.2-MariaDB-ubu2404
58 L"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"
59 " WHERE TABLE_TYPE = 'BASE TABLE'"
60 " AND TABLE_SCHEMA = DATABASE()"
61 " ORDER BY TABLE_NAME",
62 L"TRUNCATE TABLE "
63 },
64 {
65 L"Microsoft", // Microsoft SQL Server 17.00.1000
66 L"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"
67 " WHERE TABLE_TYPE = 'BASE TABLE'"
68 " AND TABLE_SCHEMA = 'dbo'"
69 " ORDER BY TABLE_NAME",
70 L"TRUNCATE TABLE "
71 },
72 {
73 L"Oracle", // [Oracle Database 21c Enterprise
74 L"SELECT TABLE_NAME FROM USER_TABLES"
75 " ORDER BY TABLE_NAME",
76 L"TRUNCATE TABLE "
77 },
78 {
79 L"PostgreSQL", // PostgreSQL 17.5 on x86_64
80 L"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"
81 " WHERE TABLE_TYPE = 'BASE TABLE'"
82 " AND TABLE_SCHEMA NOT IN ('pg_catalog', 'information_schema')"
83 " ORDER BY TABLE_NAME",
84 L"TRUNCATE TABLE "
85 },
86 {
87 L"SQLite", // SQLite 3.51.1
88 L"SELECT NAME FROM SQLITE_SCHEMA"
89 " WHERE TYPE = 'table'"
90 " ORDER BY NAME",
91 L"DELETE FROM "
92 },
93 { NULL, NULL, NULL }
94};
95
96static const DatabaseHelper* __get_helper(const String& _serverInfo)
97{
98 const DatabaseHelper* r = __database_helper__;
99 while (r->identifier) {
100 String serverInfo = _serverInfo.toLowerCase();
101 String identifier = String(r->identifier).toLowerCase();
102 if (serverInfo.indexOf(identifier) != (size_t)-1) {
103 break;
104 }
105 r++;
106 }
107 return r;
108}
109
111{
112 name = _s.name;
113 columns = _s.columns;
114 toName = _s.toName;
115 toColumns = _s.toColumns;
116}
117
119{
120 name = _s.name;
121 columns = _s.columns;
122 toName = _s.toName;
123 toColumns = _s.toColumns;
124
125 return *this;
126}
127
129{
130 return String::format(L"name[%ls] columns[%ls] toName[%ls] toColumns[%ls",
131 name.data(), columns.data(), toName.data(), toColumns.data()
132 );
133}
134
136 const MainArguments& _args,
137 const String& _srcDriver, const String& _dstDriver
139 : __args(_args), __srcConn(_srcDriver), __dstConn(_dstDriver)
140{
141 __srcHelper = __dstHelper = NULL;
142
143 __lineRuler.assign(L'-', 80);
144 __lineIndent.assign(L' ', 4);
145}
146
147static void __get_name_columns(
148 const String& _entity, String& _name, String& _columns
149)
150{
151 size_t index = _entity.indexOf(L'(');
152 if (index != (size_t)-1) {
153 _name = _entity.substring(0, index);
154 _columns = _entity.substring(index).trim().trim(L"()").trim();
155 }
156 else {
157 _name = _entity;
158 }
159}
160
161static void __verbose_out(
162 Writer& _output,
163 const String& _sql, const String& _indent
164)
165{
166 const wchar_t* begin = _sql.data();
167 const wchar_t* end = begin + _sql.length();
168 const wchar_t* p = begin;
169 while (p < end) {
170 // 길이가 70 이상이고, ' ', ',' 이전까지의 문자열을 출력한다.
171 p += 70;
172 while (p < end) {
173 if (*p == L' ' || *p == L',') {
174 break;
175 }
176 p++;
177 }
178 if (p < end) {
179 _output << _indent;
180 if (begin > _sql.data()) {
181 _output << _indent;
182 }
183 _output.write(begin, p - begin);
184 _output << endl;
185 if (*p == L' ') {
186 p++;
187 }
188 begin = p;
189 }
190 }
191 if (begin < end) {
192 _output << _indent;
193 if (begin > _sql.data()) {
194 _output << _indent;
195 }
196 _output.write(begin, end - begin);
197 _output << endl;
198 }
199}
200
203{
204 try {
205 __srcConn.open(__args.source());
206 __args.output() << L"Source database connected. ["
207 << __args.source() << L"]" << endl;
208
209 __dstConn.open(__args.destination());
210 __args.output() << L"Destination database connected. ["
211 << __args.destination() << L"]" << endl;
212 }
213 catch (Exception* _entity) {
214 __args.output() << L"Database connection failed. ["
215 << _entity->toStringAll() << L"]" << endl;
216 _entity->destroy();
217 return false;
218 }
219
220 {
221 String serverInfo = __srcConn.getServerInfo();
222 __srcHelper = __get_helper(serverInfo);
223 if (!__srcHelper) {
224 __args.output() << L"Unknown Database Vendor. ["
225 << serverInfo << L"] Failed." << endl;
226 return false;
227 }
228
229 serverInfo = __dstConn.getServerInfo();
230 __dstHelper = __get_helper(serverInfo);
231 if (!__dstHelper) {
232 __args.output() << L"Unknown Database Vendor. ["
233 << serverInfo << L"] Failed." << endl;
234 return false;
235 }
236 }
237
238 if (!__args.entities().isEmpty()) {
239 StringArray a;
240 __args.entities().split(L';', a);
241 for (size_t i = 0; i < a.size(); i++) {
242 const String& s = a[i];
243 Entity e;
244 if (s.contains(L'=')) {
245 StringArray pair;
246 s.split(L'=', pair);
247 __get_name_columns(pair[0], e.name, e.columns);
248 __get_name_columns(pair[1], e.toName, e.toColumns);
249 }
250 else {
251 __get_name_columns(s, e.name, e.columns);
252 }
253 __entities.add(e);
254 __DCL_TRACE1_N(L"entity[%ls]\n", e.toString().data());
255 }
256 }
257 else {
258 Array<Entity> srcEntities;
259 Array<Entity> dstEntities;
260
261 String srcTableSQL = __srcHelper->selectTableList;
262 String dstTableSQL = __dstHelper->selectTableList;
263
264 if (__args.verbose()) {
265 __args.output() << L"Source entities SQL" << endl;
266 __verbose_out(__args.output(), srcTableSQL, __lineIndent);
267 __args.output() << L"Destination entities SQL" << endl;
268 __verbose_out(__args.output(), dstTableSQL, __lineIndent);
269 }
270
271 __srcConn.startTrans();
272 {
274 q.execute(srcTableSQL);
275 q.fetch();
276 while (!q.eof()) {
277 Entity e;
278 e.name = q.fields()[0].asString().trim();
279 srcEntities.add(e);
280 q.fetch();
281 }
282 }
283 __srcConn.commitTrans();
284
285 __dstConn.startTrans();
286 {
288 q.execute(dstTableSQL);
289 q.fetch();
290 while (!q.eof()) {
291 Entity e;
292 e.name = q.fields()[0].asString().trim();
293 dstEntities.add(e);
294 q.fetch();
295 }
296 }
297 __dstConn.commitTrans();
298
299 if (srcEntities.size() < dstEntities.size()) {
300 __entities = srcEntities;
301 }
302 else {
303 __entities = dstEntities;
304 }
305#if __TRACE_THIS
306 StringBuilder sb = L"{";
307 for (size_t i = 0; i < __entities.size(); i++) {
308 if (i > 0) {
309 sb.append(L", ");
310 }
311 sb.append(__entities[i].name);
312 }
313 sb.append(L"}");
314 __DCL_TRACE2_N(L"__entities[%ls][%ls]\n",
315 srcEntities.size() < dstEntities.size() ? L"src" : L"dst",
316 sb.toString().data());
317#endif
318 }
319 return __entities.size() > 0;
320}
321
324{
325 switch (_field.dataType()) {
326 case SQL::typeInteger: {
327 if (_field.dataSizeMax() <= sizeof(int32_t)) {
328 int32_t value = 0;
329 _field.getValue(value);
330 _param.setValue(value);
331 }
332 else {
333 int64_t value = 0;
334 _field.getValue(value);
335 _param.setValue(value);
336 }
337 break;
338 }
339 case SQL::typeUInteger: {
340 if (_field.dataSizeMax() <= sizeof(uint32_t)) {
341 uint32_t value = 0;
342 _field.getValue(value);
343 _param.setValue(value);
344 }
345 else {
346 uint64_t value = 0;
347 _field.getValue(value);
348 _param.setValue(value);
349 }
350 break;
351 }
352 case SQL::typeFloat: {
353 if (_field.dataSizeMax() == sizeof(float)) {
354 float value = 0.;
355 _field.getValue(value);
356 _param.setValue(value);
357 }
358 else {
359 double value = 0.;
360 _field.getValue(value);
361 _param.setValue(value);
362 }
363 break;
364 }
365 case SQL::typeNumeric: {
366 if (_field.precision() > 0 && _field.scale() == 0) {
367 // 12345678901234567890
368 // 2147483647
369 // 9223372036854775807
370 if (_field.precision() <= __args.i4precision()) {
371 int32_t value = 0;
372 _field.getValue(value);
373 _param.setValue(value);
374 break;
375 }
376 else if (_field.precision() <= __args.i8precision()) {
377 int64_t value = 0;
378 _field.getValue(value);
379 _param.setValue(value);
380 break;
381 }
382 else {
383 // BigInteger
384 }
385 }
386 ByteString value;
387 _field.getValue(value, SQL::typeText);
388 _param.setValue(value, SQL::typeText);
389 break;
390 }
391 case SQL::typeDate: {
392 SQL::Date value;
393 _field.getValue(value);
394 _param.setData(&value, sizeof(value),
396 break;
397 }
398 case SQL::typeTime:
399 case SQL::typeTimeTz: {
400 SQL::Time value;
401 _field.getValue(value);
402 _param.setData(&value, sizeof(value),
404 break;
405 }
408 SQL::TimeStamp value;
409 _field.getValue(value);
410 _param.setData(&value, sizeof(value),
411 _field.dataType(), SQL::typeTimeStamp);
412 break;
413 }
416 case SQL::typeIntervalDs: {
417 SQL::Interval value;
418 _field.getValue(value);
419 _param.setData(&value, sizeof(value),
420 _field.dataType(), SQL::typeInterval);
421 break;
422 }
423 case SQL::typeText:
425 case SQL::typeClob: {
426 ByteString value;
427 _field.getValue(value, SQL::typeText);
428 _param.setValue(value, SQL::typeText);
429 break;
430 }
431 case SQL::typeBinary:
433 case SQL::typeBlob: {
434 ByteString value;
435 _field.getValue(value, SQL::typeBinary);
436 _param.setValue(value, SQL::typeBinary);
437 break;
438 }
439 default: {
440 __DCL_ASSERT(false);
441 }
442 }
443}
444
445void EntityCopy::copyEntity(const Entity& _entity)
447{
449 __args.output() << __lineRuler << endl
450 << _entity.name << L" [" << begin.toString()
451 << L"]" << endl;
452
453 int rows = 0;
454 __srcConn.startTrans();
455 {
456 String selectSQL = getSelectSQL(_entity);
457 SQLQuery select(__srcConn);
458 select.execute(selectSQL);
459
460 String insertSQL = getInsertSQL(_entity, select.fields());
461 String truncateSQL = getTruncateSQL(_entity);
462
463 if (__args.truncate()) {
464 if (__args.verbose()) {
465 __args.output() << __lineIndent << truncateSQL << endl;
466 }
467 if (!__args.dryrun()) {
468 __dstConn.startTrans();
469 __dstConn.execute(truncateSQL);
470 __dstConn.commitTrans();
471 }
472 }
473
474 if (__args.verbose()) {
475 __verbose_out(__args.output(), selectSQL, __lineIndent);
476 __verbose_out(__args.output(), insertSQL, __lineIndent);
477 }
478
479 select.fetch();
480 while (!select.eof()) {
481 __dstConn.startTrans();
482 {
483 SQLQuery insert(__dstConn);
484 insert.prepare(insertSQL);
485 __DCL_ASSERT(select.fields().count() == insert.params().count());
486
487 while (!select.eof()) {
488 rows++;
489 for (size_t i = 0; i < select.fields().count(); i++) {
490 SQLField& field = select.fields()[i];
491 SQLParam& param = insert.params()[i];
492 if (field.isNull()) {
493 param.setNull();
494 }
495 else {
496 try {
497 translateFieldValue(field, param);
498 }
499 catch (Exception* _cause) {
500 __DCL_TRACE4(L"%ls[%d][%ls] [%ls]\n",
501 _entity.name.data(), rows, field.name().data(),
502 _cause->toStringAll().data()
503 );
504 throw _cause;
505 }
506 }
507 }
508
509 if (!__args.dryrun()) {
510 insert.execute();
511 //__DCL_TRACE1_N(L"affectedRows[%zd]\n", insert.affectedRows());
512 }
513 select.fetch();
514 if (__args.rows() > 0 && (rows % __args.rows()) == 0) {
515 break;
516 }
517 }
518 }
519 __dstConn.commitTrans();
520 if (__args.verbose()) {
521 __args.output() << __lineIndent << L"COMMIT " << rows << endl;
522 }
523 }
524 }
525 __srcConn.commitTrans();
526
528 __args.output() << _entity.name
529 << L" [" << rows << L" rows transfered. " << (end - begin).toString()
530 << L"]" << endl;
531}
532
534{
535 for (size_t i = 0; i < __entities.size(); i++) {
537 }
538}
539
540String EntityCopy::getSelectSQL(const Entity& _entity)
541{
542 StringBuilder sb = L"SELECT ";
543 sb.append(!_entity.columns.isEmpty() ? _entity.columns : L"*")
544 .append(L" FROM ")
545 .append(_entity.name);
546
547 return sb;
548}
549
550String EntityCopy::getInsertSQL(const Entity& _entity, const SQLFields& _fields)
551{
552 StringBuilder sb = L"INSERT INTO ";
553 sb.append(!_entity.toName.isEmpty() ? _entity.toName : _entity.name)
554 .append(L"(");
555 if (!_entity.toColumns.isEmpty()) {
556 sb.append(_entity.toColumns);
557 }
558 else if (!_entity.columns.isEmpty()) {
559 sb.append(_entity.columns);
560 }
561 else {
562 sb.append(_fields[0].name());
563 for (size_t i = 1; i < _fields.count(); i++) {
564 sb.append(L",").append(_fields[i].name());
565 }
566 }
567 sb.append(L") VALUES (?");
568
569 for (size_t i = 1; i < _fields.count(); i++) {
570 sb.append(L",?");
571 }
572 sb.append(L")");
573
574 return sb;
575}
576
577String EntityCopy::getTruncateSQL(const Entity& _entity)
578{
579 StringBuilder sb = __dstHelper->truncateTable;
580 sb.append(!_entity.toName.isEmpty() ? _entity.toName : _entity.name);
581 return sb;
582}
583
584__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:312
wchar_t char_t
Definition Config.h:247
#define __DCL_THROWS2(e1, e2)
Definition Config.h:153
#define __DCL_THROWS1(e)
Definition Config.h:152
SQLException __srcConn(_srcDriver)
#define __DCL_TRACE2_N(fmt, arg1, arg2)
SQLException __dstConn(_dstDriver)
IOException *size_t r
Definition MediaInfo.cpp:82
#define __DCL_ASSERT(expr)
Definition Object.h:394
#define __DCL_TRACE4(fmt, arg1, arg2, arg3, arg4)
Definition Object.h:402
#define __T(str)
Definition Object.h:60
DCLCVAR const struct __endl endl
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:843
static DateTime getCurrentLocalTime()
Definition DateTime.cpp:954
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:55
@ typeBinary
Definition SQLCore.h:74
@ typeClob
Definition SQLCore.h:77
@ typeNumeric
Definition SQLCore.h:64
@ typeTime
Definition SQLCore.h:66
@ typeLongBinary
Definition SQLCore.h:76
@ typeUInteger
Definition SQLCore.h:62
@ typeTimeStamp
Definition SQLCore.h:68
@ typeBlob
Definition SQLCore.h:78
@ typeTimeStampTz
Definition SQLCore.h:69
@ typeInterval
Definition SQLCore.h:70
@ typeIntervalDs
Definition SQLCore.h:72
@ typeDate
Definition SQLCore.h:65
@ typeText
Definition SQLCore.h:73
@ typeTimeTz
Definition SQLCore.h:67
@ typeFloat
Definition SQLCore.h:63
@ typeInteger
Definition SQLCore.h:61
@ typeIntervalYm
Definition SQLCore.h:71
@ typeLongText
Definition SQLCore.h:75
size_t count() const
Definition SQL.inl:80
void prepare(const String &_sql) __DCL_THROWS1(SQLException *)
Definition SQLQuery.cpp:282
_CONST SQLParams & params() _CONST
Definition SQL.inl:106
_CONST SQLFields & fields() _CONST
Definition SQL.inl:101
void execute() __DCL_THROWS1(SQLException *)
Definition SQLQuery.cpp:316
bool eof() const
Definition SQL.inl:91
void fetch() __DCL_THROWS1(SQLException *)
Definition SQLQuery.cpp:336
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