SQLsmith  v1.2.1-5-gfacd7a8
A random SQL query generator
expr.cc
1 #include <numeric>
2 #include <algorithm>
3 #include <stdexcept>
4 #include <memory>
5 #include <cassert>
6 
7 #include "random.hh"
8 #include "relmodel.hh"
9 #include "grammar.hh"
10 #include "schema.hh"
11 #include "impedance.hh"
12 #include "expr.hh"
13 
14 using namespace std;
15 using impedance::matched;
16 
17 shared_ptr<value_expr> value_expr::factory(prod *p, sqltype *type_constraint)
18 {
19  try {
20  if (1 == d20() && p->level < d6() && window_function::allowed(p))
21  return make_shared<window_function>(p, type_constraint);
22  else if (1 == d42() && p->level < d6())
23  return make_shared<coalesce>(p, type_constraint);
24  else if (1 == d42() && p->level < d6())
25  return make_shared<nullif>(p, type_constraint);
26  else if (p->level < d6() && d6() == 1)
27  return make_shared<funcall>(p, type_constraint);
28  else if (d12()==1)
29  return make_shared<atomic_subselect>(p, type_constraint);
30  else if (p->level< d6() && d9()==1)
31  return make_shared<case_expr>(p, type_constraint);
32  else if (p->scope->refs.size() && d20() > 1)
33  return make_shared<column_reference>(p, type_constraint);
34  else
35  return make_shared<const_expr>(p, type_constraint);
36  } catch (runtime_error &e) {
37  }
38  p->retry();
39  return factory(p, type_constraint);
40 }
41 
42 case_expr::case_expr(prod *p, sqltype *type_constraint)
43  : value_expr(p)
44 {
45  condition = bool_expr::factory(this);
46  true_expr = value_expr::factory(this, type_constraint);
47  false_expr = value_expr::factory(this, true_expr->type);
48 
49  if(false_expr->type != true_expr->type) {
50  /* Types are consistent but not identical. Try to find a more
51  concrete one for a better match. */
52  if (true_expr->type->consistent(false_expr->type))
53  true_expr = value_expr::factory(this, false_expr->type);
54  else
55  false_expr = value_expr::factory(this, true_expr->type);
56  }
57  type = true_expr->type;
58 }
59 
60 void case_expr::out(std::ostream &out)
61 {
62  out << "case when " << *condition;
63  out << " then " << *true_expr;
64  out << " else " << *true_expr;
65  out << " end";
66  indent(out);
67 }
68 
70 {
71  v->visit(this);
72  condition->accept(v);
73  true_expr->accept(v);
74  false_expr->accept(v);
75 }
76 
77 column_reference::column_reference(prod *p, sqltype *type_constraint) : value_expr(p)
78 {
79  if (type_constraint) {
80  auto pairs = scope->refs_of_type(type_constraint);
81  auto picked = random_pick(pairs);
82  reference += picked.first->ident()
83  + "." + picked.second.name;
84  type = picked.second.type;
85  assert(type_constraint->consistent(type));
86  } else {
87  named_relation *r = random_pick(scope->refs);
88 
89  reference += r->ident() + ".";
90  column &c = random_pick(r->columns());
91  type = c.type;
92  reference += c.name;
93  }
94 }
95 
96 shared_ptr<bool_expr> bool_expr::factory(prod *p)
97 {
98  try {
99  if (p->level > d100())
100  return make_shared<truth_value>(p);
101  if(d6() < 4)
102  return make_shared<comparison_op>(p);
103  else if (d6() < 4)
104  return make_shared<bool_term>(p);
105  else if (d6() < 4)
106  return make_shared<null_predicate>(p);
107  else if (d6() < 4)
108  return make_shared<truth_value>(p);
109  else
110  return make_shared<exists_predicate>(p);
111 // return make_shared<distinct_pred>(q);
112  } catch (runtime_error &e) {
113  }
114  p->retry();
115  return factory(p);
116 
117 }
118 
119 exists_predicate::exists_predicate(prod *p) : bool_expr(p)
120 {
121  subquery = make_shared<query_spec>(this, scope);
122 }
123 
125 {
126  v->visit(this);
127  subquery->accept(v);
128 }
129 
130 void exists_predicate::out(std::ostream &out)
131 {
132  out << "EXISTS (";
133  indent(out);
134  out << *subquery << ")";
135 }
136 
137 distinct_pred::distinct_pred(prod *p) : bool_binop(p)
138 {
139  lhs = make_shared<column_reference>(this);
140  rhs = make_shared<column_reference>(this, lhs->type);
141 }
142 
143 comparison_op::comparison_op(prod *p) : bool_binop(p)
144 {
145  auto &idx = p->scope->schema->operators_returning_type;
146 
147  auto iters = idx.equal_range(scope->schema->booltype);
148  oper = random_pick<>(iters)->second;
149 
150  lhs = value_expr::factory(this, oper->left);
151  rhs = value_expr::factory(this, oper->right);
152 
153  if (oper->left == oper->right
154  && lhs->type != rhs->type) {
155 
156  if (lhs->type->consistent(rhs->type))
157  lhs = value_expr::factory(this, rhs->type);
158  else
159  rhs = value_expr::factory(this, lhs->type);
160  }
161 }
162 
163 coalesce::coalesce(prod *p, sqltype *type_constraint, const char *abbrev)
164  : value_expr(p), abbrev_(abbrev)
165 {
166  auto first_expr = value_expr::factory(this, type_constraint);
167  auto second_expr = value_expr::factory(this, first_expr->type);
168 
169  retry_limit = 20;
170  while(first_expr->type != second_expr->type) {
171  retry();
172  if (first_expr->type->consistent(second_expr->type))
173  first_expr = value_expr::factory(this, second_expr->type);
174  else
175  second_expr = value_expr::factory(this, first_expr->type);
176  }
177  type = second_expr->type;
178 
179  value_exprs.push_back(first_expr);
180  value_exprs.push_back(second_expr);
181 }
182 
183 void coalesce::out(std::ostream &out)
184 {
185  out << "cast(" << abbrev_ << "(";
186  for (auto expr = value_exprs.begin(); expr != value_exprs.end(); expr++) {
187  out << **expr;
188  if (expr+1 != value_exprs.end())
189  out << ",", indent(out);
190  }
191  out << ")";
192  out << " as " << type->name << ")";
193 }
194 
195 const_expr::const_expr(prod *p, sqltype *type_constraint)
196  : value_expr(p), expr("")
197 {
198  type = type_constraint ? type_constraint : scope->schema->inttype;
199 
200  if (type == scope->schema->inttype)
201  expr = to_string(d100());
202  else if (type == scope->schema->booltype)
203  expr += (d6() > 3) ? scope->schema->true_literal : scope->schema->false_literal;
204  else if (dynamic_cast<insert_stmt*>(p) && (d6() > 3))
205  expr += "default";
206  else
207  expr += "cast(null as " + type->name + ")";
208 }
209 
210 funcall::funcall(prod *p, sqltype *type_constraint, bool agg)
211  : value_expr(p), is_aggregate(agg)
212 {
213  if (type_constraint == scope->schema->internaltype)
214  fail("cannot call functions involving internal type");
215 
216  auto &idx = agg ? p->scope->schema->aggregates_returning_type
217  : (4 < d6()) ?
218  p->scope->schema->routines_returning_type
219  : p->scope->schema->parameterless_routines_returning_type;
220 
221  retry:
222 
223  if (!type_constraint) {
224  proc = random_pick(idx.begin(), idx.end())->second;
225  } else {
226  auto iters = idx.equal_range(type_constraint);
227  proc = random_pick<>(iters)->second;
228  if (proc && !type_constraint->consistent(proc->restype)) {
229  retry();
230  goto retry;
231  }
232  }
233 
234  if (!proc) {
235  retry();
236  goto retry;
237  }
238 
239  if (type_constraint)
240  type = type_constraint;
241  else
242  type = proc->restype;
243 
244  if (type == scope->schema->internaltype) {
245  retry();
246  goto retry;
247  }
248 
249  for (auto type : proc->argtypes)
250  if (type == scope->schema->internaltype
251  || type == scope->schema->arraytype) {
252  retry();
253  goto retry;
254  }
255 
256  for (auto argtype : proc->argtypes) {
257  assert(argtype);
258  auto expr = value_expr::factory(this, argtype);
259  parms.push_back(expr);
260  }
261 }
262 
263 void funcall::out(std::ostream &out)
264 {
265  out << proc->ident() << "(";
266  for (auto expr = parms.begin(); expr != parms.end(); expr++) {
267  indent(out);
268  out << "cast(" << **expr << " as " << (*expr)->type->name << ")";
269  if (expr+1 != parms.end())
270  out << ",";
271  }
272 
273  if (is_aggregate && (parms.begin() == parms.end()))
274  out << "*";
275  out << ")";
276 }
277 
278 atomic_subselect::atomic_subselect(prod *p, sqltype *type_constraint)
279  : value_expr(p), offset((d6() == 6) ? d100() : d6())
280 {
281  match();
282  if (d6() < 3) {
283  if (type_constraint) {
284  auto idx = scope->schema->aggregates_returning_type;
285  auto iters = idx.equal_range(type_constraint);
286  agg = random_pick<>(iters)->second;
287  } else {
288  agg = &random_pick<>(scope->schema->aggregates);
289  }
290  if (agg->argtypes.size() != 1)
291  agg = 0;
292  else
293  type_constraint = agg->argtypes[0];
294  } else {
295  agg = 0;
296  }
297 
298  if (type_constraint) {
299  auto idx = scope->schema->tables_with_columns_of_type;
300  col = 0;
301  auto iters = idx.equal_range(type_constraint);
302  tab = random_pick<>(iters)->second;
303 
304  for (auto &cand : tab->columns()) {
305  if (type_constraint->consistent(cand.type)) {
306  col = &cand;
307  break;
308  }
309  }
310  assert(col);
311  } else {
312  tab = &random_pick<>(scope->schema->tables);
313  col = &random_pick<>(tab->columns());
314  }
315 
316  type = agg ? agg->restype : col->type;
317 }
318 
319 void atomic_subselect::out(std::ostream &out)
320 {
321  out << "(select ";
322 
323  if (agg)
324  out << agg->ident() << "(" << col->name << ")";
325  else
326  out << col->name;
327 
328  out << " from " << tab->ident();
329 
330  if (!agg)
331  out << " limit 1 offset " << offset;
332 
333  out << ")";
334  indent(out);
335 }
336 
337 void window_function::out(std::ostream &out)
338 {
339  indent(out);
340  out << *aggregate << " over (partition by ";
341 
342  for (auto ref = partition_by.begin(); ref != partition_by.end(); ref++) {
343  out << **ref;
344  if (ref+1 != partition_by.end())
345  out << ",";
346  }
347 
348  out << " order by ";
349 
350  for (auto ref = order_by.begin(); ref != order_by.end(); ref++) {
351  out << **ref;
352  if (ref+1 != order_by.end())
353  out << ",";
354  }
355 
356  out << ")";
357 }
358 
359 window_function::window_function(prod *p, sqltype *type_constraint)
360  : value_expr(p)
361 {
362  match();
363  aggregate = make_shared<funcall>(this, type_constraint, true);
364  type = aggregate->type;
365  partition_by.push_back(make_shared<column_reference>(this));
366  while(d6() > 4)
367  partition_by.push_back(make_shared<column_reference>(this));
368 
369  order_by.push_back(make_shared<column_reference>(this));
370  while(d6() > 4)
371  order_by.push_back(make_shared<column_reference>(this));
372 }
373 
374 bool window_function::allowed(prod *p)
375 {
376  if (dynamic_cast<select_list *>(p))
377  return dynamic_cast<query_spec *>(p->pprod) ? true : false;
378  if (dynamic_cast<window_function *>(p))
379  return false;
380  if (dynamic_cast<value_expr *>(p))
381  return allowed(p->pprod);
382  return false;
383 }
grammar: Value expression productions
grammar: Top-level and unsorted grammar productions
feedback to the grammar about failed productions
randomness
supporting classes for the grammar
Base class providing schema information to grammar.
virtual void out(std::ostream &out)
Emit SQL for this production.
Definition: expr.cc:319
virtual void out(std::ostream &out)
Emit SQL for this production.
Definition: expr.cc:60
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
Definition: expr.cc:69
virtual void out(std::ostream &out)
Emit SQL for this production.
Definition: expr.cc:183
virtual void out(std::ostream &out)
Emit SQL for this production.
Definition: expr.cc:130
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
Definition: expr.cc:124
virtual void out(std::ostream &out)
Emit SQL for this production.
Definition: expr.cc:263
Base class for walking the AST.
Definition: prod.hh:11
Base class for AST nodes.
Definition: prod.hh:17
virtual void indent(std::ostream &out)
Newline and indent according to tree level.
Definition: prod.cc:20
void retry()
Increase the retry count and throw an exception when retry_limit is exceeded.
Definition: prod.cc:27
struct scope * scope
Scope object to model column/table reference visibility.
Definition: prod.hh:22
long retry_limit
Maximum number of retries allowed before reporting a failure to the Parent prod.
Definition: prod.hh:30
int level
Level of this production in the AST. 0 for root node.
Definition: prod.hh:24
struct prod * pprod
Parent production that instanciated this one.
Definition: prod.hh:20
virtual void fail(const char *reason)
Report a "failed to generate" error.
Definition: prod.cc:44
virtual void match()
Check with the impedance matching code whether this production has been blacklisted and throw an exce...
Definition: prod.cc:38
vector< named_relation * > refs
available to column_ref productions
Definition: relmodel.hh:84
virtual bool consistent(struct sqltype *rvalue)
This function is used to model postgres-style pseudotypes.
Definition: relmodel.cc:13
virtual void out(std::ostream &out)
Emit SQL for this production.
Definition: expr.cc:337