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