SQLsmith  v1.2.1-5-gfacd7a8
A random SQL query generator
log.cc
1 #include "config.h"
2 #include <iostream>
3 #include <pqxx/pqxx>
4 #include <sstream>
5 
6 #ifndef HAVE_BOOST_REGEX
7 #include <regex>
8 #else
9 #include <boost/regex.hpp>
10 using boost::regex;
11 using boost::smatch;
12 using boost::regex_match;
13 #endif
14 
15 #include <string>
16 
17 extern "C" {
18 #include <unistd.h>
19 }
20 
21 #include "log.hh"
22 #include "schema.hh"
23 #include "gitrev.h"
24 #include "impedance.hh"
25 #include "random.hh"
26 
27 using namespace std;
28 using namespace pqxx;
29 
31  int nodes = 0;
32  int maxlevel = 0;
33  long retries = 0;
34  map<const char*, long> production_stats;
35  virtual void visit(struct prod *p) {
36  nodes++;
37  if (p->level > maxlevel)
38  maxlevel = p->level;
39  production_stats[typeid(*p).name()]++;
40  retries += p->retries;
41  }
42  void report() {
43  cerr << "production statistics" << endl;
44  vector<pair<const char *, long> > report;
45  for (auto p : production_stats)
46  report.push_back(p);
47  stable_sort(report.begin(), report.end(),
48  [](const pair<std::string, long> &a,
49  const pair<std::string, long> &b)
50  { return a.second > b.second; });
51  for (auto p : report) {
52  cerr << p.second << "\t" << p.first << endl;
53  }
54  }
55 };
56 
57 void stats_collecting_logger::generated(prod &query)
58 {
59  queries++;
60 
61  stats_visitor v;
62  query.accept(&v);
63 
64  sum_nodes += v.nodes;
65  sum_height += v.maxlevel;
66  sum_retries += v.retries;
67 }
68 
69 void cerr_logger::report()
70 {
71  cerr << endl << "queries: " << queries << endl;
72 // << " (" << 1000.0*query_count/gen_time.count() << " gen/s, "
73 // << 1000.0*query_count/query_time.count() << " exec/s)" << endl;
74  cerr << "AST stats (avg): height = " << sum_height/queries
75  << " nodes = " << sum_nodes/queries << endl;
76 
77  vector<pair<std::string, long> > report;
78  for (auto e : errors) {
79  report.push_back(e);
80  }
81  stable_sort(report.begin(), report.end(),
82  [](const pair<std::string, long> &a,
83  const pair<std::string, long> &b)
84  { return a.second > b.second; });
85  long err_count = 0;
86  for (auto e : report) {
87  err_count += e.second;
88  cerr << e.second << "\t" << e.first.substr(0,80) << endl;
89  }
90  cerr << "error rate: " << (float)err_count/(queries) << endl;
91  impedance::report();
92 }
93 
94 
95 void cerr_logger::generated(prod &p)
96 {
97  stats_collecting_logger::generated(p);
98  if ((10*columns-1) == queries%(10*columns))
99  report();
100 }
101 
102 void cerr_logger::executed(prod &query)
103 {
104  (void)query;
105  if (columns-1 == (queries%columns)) {
106  cerr << endl;
107  }
108  cerr << ".";
109 }
110 
111 void cerr_logger::error(prod &query, const dut::failure &e)
112 {
113  (void)query;
114  istringstream err(e.what());
115  string line;
116 
117  if (columns-1 == (queries%columns)) {
118  cerr << endl;
119  }
120  getline(err, line);
121  errors[line]++;
122  if (dynamic_cast<const dut::timeout *>(&e))
123  cerr << "t";
124  else if (dynamic_cast<const dut::syntax *>(&e))
125  cerr << "S";
126  else if (dynamic_cast<const dut::broken *>(&e))
127  cerr << "C";
128  else
129  cerr << "e";
130 }
131 
132 pqxx_logger::pqxx_logger(std::string target, std::string conninfo, struct schema &s)
133 {
134  c = make_shared<pqxx::connection>(conninfo);
135 
136  work w(*c);
137  w.exec("set application_name to '" PACKAGE "::log';");
138 
139  c->prepare("instance",
140  "insert into instance (rev, target, hostname, version, seed) "
141  "values ($1, $2, $3, $4, $5) returning id");
142 
143  char hostname[1024];
144  gethostname(hostname, sizeof(hostname));
145 
146  ostringstream seed;
147  seed << smith::rng;
148 
149  result r = w.prepared("instance")(GITREV)(target)(hostname)(s.version)(seed.str()).exec();
150 
151  id = r[0][0].as<long>(id);
152 
153  c->prepare("error",
154  "insert into error (id, msg, query, sqlstate) "
155  "values (" + to_string(id) + ", $1, $2, $3)");
156 
157  w.exec("insert into stat (id) values (" + to_string(id) + ")");
158  c->prepare("stat",
159  "update stat set generated=$1, level=$2, nodes=$3, updated=now() "
160  ", retries = $4, impedance = $5 "
161  "where id = " + to_string(id));
162 
163  w.commit();
164 
165 }
166 
167 void pqxx_logger::error(prod &query, const dut::failure &e)
168 {
169  work w(*c);
170  ostringstream s;
171  s << query;
172  w.prepared("error")(e.what())(s.str())(e.sqlstate).exec();
173  w.commit();
174 }
175 
176 void pqxx_logger::generated(prod &query)
177 {
178  stats_collecting_logger::generated(query);
179  if (999 == (queries%1000)) {
180  work w(*c);
181  ostringstream s;
182  impedance::report(s);
183  w.prepared("stat")(queries)(sum_height/queries)(sum_nodes/queries)(sum_retries/queries)(s.str()).exec();
184  w.commit();
185  }
186 }
187 
feedback to the grammar about failed productions
logging
randomness
Base class providing schema information to grammar.
Base class for walking the AST.
Definition: prod.hh:11
Base class for AST nodes.
Definition: prod.hh:17
int level
Level of this production in the AST. 0 for root node.
Definition: prod.hh:24
long retries
Number of retries in this production.
Definition: prod.hh:27
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
Definition: prod.hh:41
Definition: schema.hh:16