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