15 shared_ptr<table_ref> table_ref::factory(
prod *p) {
17 if (p->
level < 3 + d6()) {
18 if (d6() > 3 && p->
level < d6())
19 return make_shared<table_subquery>(p);
21 return make_shared<joined_table>(p);
24 return make_shared<table_or_query_name>(p);
26 return make_shared<table_sample>(p);
27 }
catch (runtime_error &e) {
33 table_or_query_name::table_or_query_name(
prod *p) :
table_ref(p) {
35 refs.push_back(make_shared<aliased_relation>(
scope->
stmt_uid(
"ref"), t));
39 out << t->ident() <<
" as " << refs[0]->ident();
45 || victim->schema ==
"pg_catalog"
46 || !victim->is_base_table
47 || !victim->columns().size()) {
49 victim =
dynamic_cast<table *
>(pick);
53 refs.push_back(make_shared<aliased_relation>(
scope->
stmt_uid(
"target"), victim));
57 out << victim_->ident() <<
" as " << refs[0]->ident();
64 auto pick = random_pick(
scope->schema->base_tables);
65 t =
dynamic_cast<struct
table*
>(pick);
67 }
while (!t || !t->is_base_table);
69 refs.push_back(make_shared<aliased_relation>(
scope->
stmt_uid(
"sample"), t));
70 percent = 0.1 * d100();
71 method = (d6() > 2) ?
"system" :
"bernoulli";
76 " as " << refs[0]->ident() <<
77 " tablesample " << method <<
78 " (" << percent <<
") ";
81 table_subquery::table_subquery(
prod *p,
bool lateral)
83 query = make_shared<query_spec>(
this,
scope, lateral);
85 relation *aliased_rel = &query->select_list->derived_table;
86 refs.push_back(make_shared<aliased_relation>(alias, aliased_rel));
89 table_subquery::~table_subquery() { }
100 return make_shared<expr_join_cond>(p, lhs, rhs);
102 return make_shared<simple_join_cond>(p, lhs, rhs);
103 }
catch (runtime_error &e) {
106 return factory(p, lhs, rhs);
115 if (!left_rel->columns().size())
120 column &c1 = random_pick(left_rel->columns());
122 for (
auto c2 : right_rel->columns()) {
123 if (c1.type == c2.type) {
125 left_rel->ident() +
"." + c1.name +
" = " + right_rel->ident() +
"." + c2.name +
" ";
129 if (condition ==
"") {
142 for (
auto ref: lhs.refs)
143 joinscope.
refs.push_back(&*ref);
144 for (
auto ref: rhs.refs)
145 joinscope.refs.push_back(&*ref);
146 search = bool_expr::factory(
this);
154 lhs = table_ref::factory(
this);
155 rhs = table_ref::factory(
this);
157 condition = join_cond::factory(
this, *lhs, *rhs);
167 for (
auto ref: lhs->refs)
169 for (
auto ref: rhs->refs)
176 out << type <<
" join " << *rhs;
178 out <<
"on (" << *condition <<
")";
184 out <<
"(" << *query <<
") as " << refs[0]->ident();
188 if (! reflist.size())
192 for (
auto r = reflist.begin(); r < reflist.end(); r++) {
195 if (r + 1 != reflist.end())
200 from_clause::from_clause(
prod *p) :
prod(p) {
201 reflist.push_back(table_ref::factory(
this));
202 for (
auto r : reflist.back()->refs)
209 reflist.push_back(make_shared<lateral_subquery>(
this));
210 for (
auto r : reflist.back()->refs)
215 select_list::select_list(
prod *p) :
prod(p)
218 shared_ptr<value_expr> e = value_expr::factory(
this);
219 value_exprs.push_back(e);
221 name <<
"c" << columns++;
224 derived_table.columns().push_back(
column(name.str(), t));
231 for (
auto expr = value_exprs.begin(); expr != value_exprs.end(); expr++) {
233 out << **expr <<
" as " << derived_table.columns()[i].name;
235 if (expr+1 != value_exprs.end())
241 out <<
"select " << set_quantifier <<
" "
248 if (limit_clause.length()) {
255 virtual void visit(
prod *p) {
257 throw(
"window function");
259 if (join && join->type !=
"inner")
263 subquery->set_quantifier =
"";
266 table *actual_table =
dynamic_cast<table*
>(tab->t);
267 if (actual_table && !actual_table->is_insertable)
269 if (actual_table->name.find(
"pg_"))
274 table *actual_table =
dynamic_cast<table*
>(sample->t);
275 if (actual_table && !actual_table->is_insertable)
277 if (actual_table->name.find(
"pg_"))
284 select_for_update::select_for_update(
prod *p,
struct scope *s,
bool lateral)
287 static const char *modes[] = {
298 }
catch (
const char* reason) {
302 lockmode = modes[d6()%(
sizeof(modes)/
sizeof(*modes))];
310 out <<
" for " << lockmode;
314 query_spec::query_spec(
prod *p,
struct scope *s,
bool lateral) :
323 from_clause = make_shared<struct from_clause>(
this);
324 select_list = make_shared<struct select_list>(
this);
326 set_quantifier = (d100() == 1) ?
"distinct" :
"";
328 search = bool_expr::factory(
this);
332 cons <<
"limit " << d100() + d100();
333 limit_clause = cons.str();
337 long prepare_stmt::seq;
339 void modifying_stmt::pick_victim()
343 victim =
dynamic_cast<struct
table*
>(pick);
346 || victim->schema ==
"pg_catalog"
347 || !victim->is_base_table
348 || !victim->columns().size());
351 modifying_stmt::modifying_stmt(
prod *p,
struct scope *s,
table *victim)
352 :
prod(p), myscope(s)
365 search = bool_expr::factory(
this);
368 delete_returning::delete_returning(
prod *p,
struct scope *s,
table *victim)
371 select_list = make_shared<struct select_list>(
this);
379 for (
auto col : victim->columns()) {
380 auto expr = value_expr::factory(
this, col.type);
381 assert(expr->type == col.type);
382 value_exprs.push_back(expr);
388 out <<
"insert into " << victim->ident() <<
" ";
390 if (!value_exprs.size()) {
391 out <<
"default values";
397 for (
auto expr = value_exprs.begin();
398 expr != value_exprs.end();
402 if (expr+1 != value_exprs.end())
411 for (
auto col : target->columns()) {
414 auto expr = value_expr::factory(
this, col.type);
415 value_exprs.push_back(expr);
416 names.push_back(col.name);
418 }
while (!names.size());
423 assert(names.size());
425 for (
size_t i = 0; i < names.size(); i++) {
427 out << names[i] <<
" = " << *value_exprs[i];
428 if (i+1 != names.size())
436 search = bool_expr::factory(
this);
437 set_list = make_shared<struct set_list>(
this, victim);
445 update_returning::update_returning(
prod *p,
struct scope *s,
table *v)
449 select_list = make_shared<struct select_list>(
this);
458 if (!victim->constraints.size())
459 fail(
"need table w/ constraint for upsert");
461 set_list = std::make_shared<struct set_list>(
this, victim);
462 search = bool_expr::factory(
this);
463 constraint = random_pick(victim->constraints);
466 shared_ptr<prod> statement_factory(
struct scope *s)
471 return make_shared<merge_stmt>((
struct prod *)0, s);
473 return make_shared<insert_stmt>((
struct prod *)0, s);
475 return make_shared<delete_returning>((
struct prod *)0, s);
476 else if (d42() == 1) {
477 return make_shared<upsert_stmt>((
struct prod *)0, s);
478 }
else if (d42() == 1)
479 return make_shared<update_returning>((
struct prod *)0, s);
481 return make_shared<select_for_update>((
struct prod *)0, s);
483 return make_shared<common_table_expression>((
struct prod *)0, s);
484 return make_shared<query_spec>((
struct prod *)0, s);
485 }
catch (runtime_error &e) {
486 return statement_factory(s);
493 for(
auto q : with_queries)
498 common_table_expression::common_table_expression(
prod *parent,
struct scope *s)
499 :
prod(parent), myscope(s)
503 shared_ptr<query_spec> query = make_shared<query_spec>(
this, s);
504 with_queries.push_back(query);
507 auto aliased_rel = make_shared<aliased_relation>(alias,
relation);
508 refs.push_back(aliased_rel);
515 auto pick = random_pick(s->
tables);
519 query = make_shared<query_spec>(
this,
scope);
520 }
catch (runtime_error &e) {
530 for (
size_t i = 0; i < with_queries.size(); i++) {
532 out << refs[i]->ident() <<
" AS " <<
"(" << *with_queries[i] <<
")";
533 if (i+1 != with_queries.size())
544 target_table_ = make_shared<target_table>(
this, victim);
545 data_source = table_ref::factory(
this);
547 join_condition = make_shared<simple_join_cond>(
this, *target_table_, *data_source);
555 clauselist.push_back(when_clause::factory(
this));
557 clauselist.push_back(when_clause::factory(
this));
562 out <<
"MERGE INTO " << *target_table_;
564 out <<
"USING " << *data_source;
566 out <<
"ON " << *join_condition;
568 for (
auto p : clauselist) {
577 target_table_->accept(v);
578 data_source->accept(v);
579 join_condition->accept(v);
580 for (
auto p : clauselist)
588 condition = bool_expr::factory(
this);
594 out << (matched ?
"WHEN MATCHED " :
"WHEN NOT MATCHED");
596 out <<
"AND " << *condition;
599 out << (matched ?
"DELETE" :
"DO NOTHING");
605 condition->accept(v);
608 when_clause_update::when_clause_update(
merge_stmt *p)
614 scope->
refs.push_back(&*(p->target_table_->refs[0]));
616 set_list = std::make_shared<struct set_list>(
this, p->victim);
620 out <<
"WHEN MATCHED AND " << *condition;
632 when_clause_insert::when_clause_insert(
struct merge_stmt *p)
635 for (
auto col : p->victim->columns()) {
636 auto expr = value_expr::factory(
this, col.type);
637 assert(expr->type == col.type);
638 exprs.push_back(expr);
643 out <<
"WHEN NOT MATCHED AND " << *condition;
645 out <<
" THEN INSERT VALUES ( ";
647 for (
auto expr = exprs.begin();
651 if (expr+1 != exprs.end())
665 shared_ptr<when_clause> when_clause::factory(
struct merge_stmt *p)
671 return make_shared<when_clause_insert>(p);
674 return make_shared<when_clause_update>(p);
676 return make_shared<when_clause>(p);
678 }
catch (runtime_error &e) {
grammar: Top-level and unsorted grammar productions
feedback to the grammar about failed productions
supporting classes for the grammar
Base class providing schema information to grammar.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
virtual void out(std::ostream &out)
Emit SQL for this production.
Base class for walking the AST.
Base class for AST nodes.
virtual void indent(std::ostream &out)
Newline and indent according to tree level.
void retry()
Increase the retry count and throw an exception when retry_limit is exceeded.
long retry_limit
Maximum number of retries allowed before reporting a failure to the Parent prod.
int level
Level of this production in the AST. 0 for root node.
virtual void fail(const char *reason)
Report a "failed to generate" error.
virtual void match()
Check with the impedance matching code whether this production has been blacklisted and throw an exce...
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
virtual void out(std::ostream &out)
Emit SQL for this production.
void new_stmt()
Reset unique identifier counters.
vector< named_relation * > tables
available to table_ref productions
vector< named_relation * > refs
available to column_ref productions
string stmt_uid(const char *prefix)
Generate unique identifier with prefix.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void out(std::ostream &out)
Emit SQL for this production.
virtual void accept(prod_visitor *v)
Visitor pattern for walking the AST.