MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
validate_json.py
1 #! /usr/bin/python
2 
3 # Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
17 
18 import sys
19 
20 usage = """
21 This is from WL#5257 "first API for optimizer trace".
22 
23 Usage:
24  %s [-q] <a_file> <another_file> <etc>
25 
26  -q quiet mode: only display errors and warnings.
27 
28 It will verify that all optimizer traces of files (usually a_file
29 is a .result or .reject file which contains
30 SELECT * FROM OPTIMIZER_TRACE; ) are JSON-compliant, and that
31 they contain no duplicates keys.
32 Exit code is 0 if all ok.
33 """ % sys.argv[0]
34 
35 input_files = filter(lambda x: x != '-q', sys.argv[1:]) # filter out "-q" options
36 
37 if not input_files:
38  print usage
39  sys.exit(1)
40 
41 quiet = len(input_files) < len(sys.argv) - 1 # command line contains at least one "-q" option
42 
43 import json, re
44 
45 trace_start_re = re.compile(r"^.*(\t)?{\n")
46 trace_end_re = re.compile(r"^}")
47 ignorable_re = re.compile(r"^.*(ctype_.*|mysqldump)\.result")
48 
49 def check(trace, first_trace_line):
50  global retcode
51  s = "".join(trace)
52  try:
53  parsed = json.loads(s)
54  except:
55  print "parse error at line", first_trace_line
56  error = str(sys.exc_info())
57  print error
58  # if there is a character position specified, put a mark ('&')
59  # in front of this character
60  matchobj = re.search(r"ValueError\('Invalid control character at: line \d+ column \d+ \(char (\d+)\)'", error)
61  if matchobj:
62  first_error_char = int(matchobj.group(1))
63  print s[:first_error_char] + "&" + s[first_error_char:]
64  else:
65  print s
66  retcode = 1
67  print
68  return
69  # detect non-unique keys in one object, by counting
70  # number of quote symbols ("'): the json module outputs only
71  # one of the non-unique keys, making the number of " and '
72  # smaller compared to the input string.
73  before = s.count('"') + s.count("'")
74  str_parsed = str(parsed)
75  after = str_parsed.count('"') + str_parsed.count("'")
76  if (before != after):
77  print "non-unique keys at line %d (%d vs %d)" % (first_trace_line, before, after)
78  print s
79  retcode = 1
80  print
81  return
82  if not quiet:
83  print "ok at line", first_trace_line
84 
85 def handle_one_file(name):
86  if ignorable_re.match(name):
87  ignored.append(name)
88  return
89  print "FILE %s" % name
90  print
91  all = open(name).readlines()
92  first_trace_line = trace_line = 0
93  trace = None
94  for l in all:
95  trace_line += 1
96  if trace_start_re.match(l) and first_trace_line == 0:
97  trace = []
98  first_trace_line = trace_line
99  trace.append("{\n")
100  continue
101  if trace_end_re.match(l):
102  assert first_trace_line != 0
103  trace.append("}") # eliminate any following columns of table (MISSING_PRIVILEGES etc)
104  check(trace, first_trace_line)
105  first_trace_line = 0
106  if first_trace_line != 0:
107  # eliminate /* */ from end_marker=on (not valid JSON)
108  no_comment = re.sub("/\*.*\*/", "", l)
109  trace.append(no_comment)
110 
111 retcode=0
112 ignored=[]
113 for f in input_files:
114  handle_one_file(f)
115  print
116 if ignored:
117  print >>sys.stderr, "Those files have been ignored", ignored
118 print
119 if retcode:
120  print >>sys.stderr, "THERE ARE ERRORS"
121 else:
122  print "ALL OK"
123 sys.exit(retcode)