1 #!/usr/bin/env python3.2 |
1 #!/usr/bin/env python3.2 |
2 # |
2 # |
3 # Copy data between tables with same table schema. |
3 # Copy data between tables with same table schema. |
4 # |
4 # |
|
5 # Copies full table, target table must be empty. |
5 # Can copy multiple tables in one run. |
6 # Can copy multiple tables in one run. |
6 # Sorts the tables according to references. |
7 # Sorts the tables according to references. |
7 # |
8 # |
8 # This may be used instead of dump/restore. |
9 # This may be used instead of dump/restore. |
9 # |
10 # |
15 |
16 |
16 |
17 |
17 class TableCopyTool(toolbase.SrcDstTablesTool): |
18 class TableCopyTool(toolbase.SrcDstTablesTool): |
18 def __init__(self): |
19 def __init__(self): |
19 toolbase.SrcDstTablesTool.__init__(self, name='tablecopy', desc='Table copy tool.') |
20 toolbase.SrcDstTablesTool.__init__(self, name='tablecopy', desc='Table copy tool.') |
20 |
21 |
21 self.parser.add_argument('-n', '--no-action', dest='noaction', action='store_true', |
22 self.parser.add_argument('-n', '--no-action', dest='noaction', action='store_true', |
22 help="Do nothing, just print tables to be copied. Useful in combination with --regex.") |
23 help="Do nothing, just print tables to be copied. Useful in combination with --regex.") |
23 self.parser.add_argument('--no-sort', dest='nosort', action='store_true', |
24 self.parser.add_argument('--no-sort', dest='nosort', action='store_true', |
24 help="Do not sort. By default, tables are sorted by foreign key references.") |
25 help="Do not sort. By default, tables are sorted by foreign key references.") |
25 |
26 |
26 self.init() |
27 self.init() |
27 |
28 |
28 def main(self): |
29 def main(self): |
29 self.srcconn = self.pgm.get_conn('src') |
30 self.srcconn = self.pgm.get_conn('src') |
30 self.dstconn = self.pgm.get_conn('dst') |
31 self.dstconn = self.pgm.get_conn('dst') |
31 |
32 |
32 dc = pgdatacopy.PgDataCopy(self.srcconn, self.dstconn) |
33 dc = pgdatacopy.PgDataCopy(self.srcconn, self.dstconn) |
33 |
34 |
34 if self.args.nosort: |
35 if self.args.nosort: |
35 for table in self.tables(): |
36 for table in self.tables(): |
36 self.copy_table(dc, *table) |
37 self.copy_table(dc, *table) |
37 else: |
38 else: |
38 # sort tables with respect to references |
39 # sort tables with respect to references |
39 details = dict() |
40 details = dict() |
40 pending = set() |
41 pending = set() |
41 references = dict() |
42 references = dict() |
42 |
43 |
43 # build list of all table to be copied (pending) and references map |
44 # build list of all table to be copied (pending) and references map |
44 for table in self.tables(): |
45 for table in self.tables(): |
45 srcschema, srctable, dstschema, dsttable = table |
46 srcschema, srctable, dstschema, dsttable = table |
46 name = dstschema + '.' + dsttable |
47 name = dstschema + '.' + dsttable |
47 details[name] = table |
48 details[name] = table |
48 pending.add(name) |
49 pending.add(name) |
49 references[name] = self.get_references(dstschema, dsttable) |
50 references[name] = self.get_references(dstschema, dsttable) |
50 |
51 |
51 # copy files with fulfilled references, repeat until all done |
52 # copy files with fulfilled references, repeat until all done |
52 while pending: |
53 while pending: |
53 for name in list(pending): |
54 for name in list(pending): |
54 ok = True |
55 ok = True |
55 for ref in references[name]: |
56 for ref in references[name]: |
67 |
68 |
68 def copy_table(self, dc, srcschema, srctable, dstschema, dsttable): |
69 def copy_table(self, dc, srcschema, srctable, dstschema, dsttable): |
69 print('Copying [%s] %s.%s --> [%s] %s.%s' % ( |
70 print('Copying [%s] %s.%s --> [%s] %s.%s' % ( |
70 self.args.src, srcschema, srctable, |
71 self.args.src, srcschema, srctable, |
71 self.args.dst, dstschema, dsttable)) |
72 self.args.dst, dstschema, dsttable)) |
72 |
73 |
73 if self.args.noaction: |
74 if self.args.noaction: |
74 return |
75 return |
75 |
76 |
76 dc.set_source(srctable, srcschema) |
77 dc.set_source(srctable, srcschema) |
77 dc.set_destination(dsttable, dstschema) |
78 dc.set_destination(dsttable, dstschema) |
78 |
79 |
79 try: |
80 try: |
80 dc.check() |
81 dc.check() |
81 except pgdatacopy.TargetNotEmptyError as e: |
82 except pgdatacopy.TargetNotEmptyError as e: |
82 print(' - error:', str(e)) |
83 print(' - error:', str(e)) |
83 return |
84 return |
84 |
85 |
85 print(' - read ') |
86 print(' - read ') |
86 buf = io.BytesIO() |
87 buf = io.BytesIO() |
87 wrapped = ProgressWrapper(buf) |
88 wrapped = ProgressWrapper(buf) |
88 dc.read(wrapped) |
89 dc.read(wrapped) |
89 data = buf.getvalue() |
90 data = buf.getvalue() |
90 buf.close() |
91 buf.close() |
91 |
92 |
92 print(' - write ') |
93 print(' - write ') |
93 buf = io.BytesIO(data) |
94 buf = io.BytesIO(data) |
94 wrapped = ProgressWrapper(buf, len(data)) |
95 wrapped = ProgressWrapper(buf, len(data)) |
95 dc.write(wrapped) |
96 dc.write(wrapped) |
96 buf.close() |
97 buf.close() |
97 |
98 |
98 print(' - analyze ') |
99 print(' - analyze ') |
99 dc.analyze() |
100 dc.analyze() |
100 |
101 |
101 |
102 |
102 tool = TableCopyTool() |
103 tool = TableCopyTool() |