]> git.phdru.name Git - sqlconvert.git/blob - scripts/mysql2sql
Build(GHActions): Use `checkout@v4` instead of outdated `v2`
[sqlconvert.git] / scripts / mysql2sql
1 #! /usr/bin/env python
2 from __future__ import print_function
3
4 import argparse
5 from io import open
6 import os
7 import sys
8
9 from sqlconvert.print_tokens import print_tokens
10 from sqlconvert.process_mysql import is_directive_statement, process_statement
11 from sqlconvert.process_tokens import is_newline_statement, StatementGrouper
12
13 from m_lib.defenc import default_encoding
14 from m_lib.pbar.tty_pbar import ttyProgressBar
15
16 try:
17     text_type = unicode
18 except NameError:
19     text_type = str
20
21
22 def get_fsize(fp):
23     try:
24         fp.seek(0, os.SEEK_END)
25     except IOError:
26         return None  # File size is unknown
27     size = fp.tell()
28     fp.seek(0, os.SEEK_SET)
29     return size
30
31
32 def main(infile, encoding, outfile, output_encoding, use_pbar, quoting_style):
33     if use_pbar:
34         size = get_fsize(infile)
35         if size is None:
36             use_pbar = False
37
38     if use_pbar:
39         print("Converting", end='', file=sys.stderr)
40         if infile.name != '<stdin>':
41             print(' ' + infile.name, end='', file=sys.stderr)
42         print(": ", end='', file=sys.stderr)
43         sys.stderr.flush()
44
45     if use_pbar:
46         pbar = ttyProgressBar(0, size-1)
47         cur_pos = 0
48
49     grouper = StatementGrouper(encoding=encoding)
50     got_directive = False
51     for line in infile:
52         if use_pbar:
53             if isinstance(line, text_type):
54                 cur_pos += len(line.encode(encoding))
55             else:
56                 cur_pos += len(line)
57             pbar.display(cur_pos)
58         grouper.process_line(line)
59         for statement in grouper.get_statements():
60             if got_directive and is_newline_statement(statement):
61                 # Condense a sequence of newlines after a /*! directive */;
62                 got_directive = False
63                 continue
64             got_directive = is_directive_statement(statement)
65             if got_directive:
66                 continue
67             for _statement in process_statement(statement, quoting_style):
68                 print_tokens(_statement, outfile=outfile,
69                              encoding=output_encoding)
70     tokens = grouper.close()
71     if tokens:
72         for token in tokens:
73             print_tokens(token, outfile=outfile, encoding=output_encoding)
74
75     if use_pbar:
76         pbar.erase()
77         print("done.")
78
79 if __name__ == '__main__':
80     parser = argparse.ArgumentParser(description='Convert MySQL to SQL')
81     parser.add_argument('-e', '--encoding', default='utf-8',
82                         help='input/output encoding, default is utf-8')
83     parser.add_argument('-E', '--output-encoding',
84                         help='separate output encoding, default is the same '
85                         'as -e except for console; for console output '
86                         'charset from the current locale is used')
87     parser.add_argument('-m', '--mysql', action='store_true',
88                         help='MySQL/MariaDB quoting style')
89     parser.add_argument('-p', '--pg', '--postgres', action='store_true',
90                         help='PostgreSQL quoting style')
91     parser.add_argument('-s', '--sqlite', action='store_true',
92                         help='Generic SQL/SQLite quoting style; '
93                         'this is the default')
94     parser.add_argument('-o', '--outfile', help='output file name')
95     parser.add_argument('-P', '--no-pbar', action='store_true',
96                         help='inhibit progress bar')
97     parser.add_argument('infile', help='input file name')
98     parser.add_argument('output_file', nargs='?', help='output file name')
99     args = parser.parse_args()
100
101     if int(args.mysql) + int(args.pg) + int(args.sqlite) > 1:
102         print("Error: options -m/-p/-s are mutually incompatible, "
103               "use only one of them",
104               file=sys.stderr)
105         parser.print_help()
106         sys.exit(1)
107
108     if args.infile:
109         if args.infile == '-':
110             infile = sys.stdin
111         else:
112             infile = open(args.infile, 'rt', encoding=args.encoding)
113     else:
114         infile = sys.stdin
115
116     if infile.isatty():
117         print("Error: cannot read from console", file=sys.stderr)
118         parser.print_help()
119         sys.exit(1)
120
121     if args.outfile:
122         if args.output_file:
123             print("Error: too many output files", file=sys.stderr)
124             parser.print_help()
125             sys.exit(1)
126
127         outfile = args.outfile
128
129     elif args.output_file:
130         outfile = args.output_file
131
132     else:
133         outfile = '-'
134
135     if args.output_encoding:
136         output_encoding = args.output_encoding
137     elif outfile == '-':
138         output_encoding = default_encoding
139     else:
140         output_encoding = args.encoding
141
142     if outfile == '-':
143         outfile = sys.stdout
144         args.no_pbar = True
145     else:
146         try:
147             outfile = open(outfile, 'wt', encoding=output_encoding)
148         except:
149             if infile is not sys.stdin:
150                 infile.close()
151             raise
152
153     if args.mysql:
154         quoting_style = 'mysql'
155     elif args.pg:
156         quoting_style = 'postgres'
157     else:
158         quoting_style = 'sqlite'
159
160     main(infile, args.encoding, outfile, output_encoding, not args.no_pbar,
161          quoting_style)