TEST_F(BinderCorrectnessTest, DeleteStatementTest) { SetupTables(); auto& parser = parser::PostgresParser::GetInstance(); catalog::Catalog* catalog_ptr = catalog::Catalog::GetInstance(); oid_t db_oid = catalog_ptr->GetDatabaseWithName(DEFAULT_DB_NAME)->GetOid(); oid_t tableB_oid = catalog_ptr->GetTableWithName(DEFAULT_DB_NAME, "b")->GetOid(); string deleteSQL = "DELETE FROM b WHERE 1 = b1 AND b2 = 'str'"; unique_ptr<binder::BindNodeVisitor> binder(new binder::BindNodeVisitor()); auto parse_tree = parser.BuildParseTree(deleteSQL); auto deleteStmt = dynamic_cast<parser::DeleteStatement*>(parse_tree->GetStatements().at(0)); binder->BindNameToNode(deleteStmt); LOG_INFO("Checking first condition in where clause"); auto tupleExpr = (expression::TupleValueExpression*)deleteStmt->expr->GetChild(0) ->GetChild(1); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableB_oid, 0)); LOG_INFO("Checking second condition in where clause"); tupleExpr = (expression::TupleValueExpression*)deleteStmt->expr->GetChild(1) ->GetChild(0); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableB_oid, 1)); // Delete the test database auto& txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); catalog_ptr->DropDatabaseWithName(DEFAULT_DB_NAME, txn); txn_manager.CommitTransaction(txn); }
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // alias widget SetupWidgetAlias(); // init CreateActions(); CreateMainMenus(); CreateToolBar(); // setup table editWindow = new EditWindow(0); setCentralWidget(editWindow); // setup table SetupTables(); //connect signal-slot SetupConnectWidgets(); }
void SplitLoops(BlockCFG *base_cfg, Vector<BlockCFG*> *result_cfg_list) { // get the CFG which will eventually become the loop-free outer function CFG. BlockCFG *func_cfg; if (base_cfg->GetId()->Kind() == B_FunctionWhole) { // make an ID for the outer function body. Variable *function_info = base_cfg->GetId()->BaseVar(); function_info->IncRef(); BlockId *outer_id = BlockId::Make(B_Function, function_info); // make the function CFG by cloning the base CFG with the new ID. func_cfg = BlockCFG::Make(outer_id); CopyCFGLocationsVariables(base_cfg, func_cfg); CopyCFGPointsEdges(base_cfg, func_cfg); } else if (base_cfg->GetId()->Kind() == B_Function) { // this call came from a recursive invocation of SplitLoops after we // removed an irreducible loop from the function. func_cfg = base_cfg; } else { // just destructively update the original CFG. base_cfg->IncRef(); func_cfg = base_cfg; } // add a new entry point with a skip edge to the original entry point. // loop splitting breaks if the entry point is marked as a loop head. PPoint entry = func_cfg->GetEntryPoint(); Location *loc = func_cfg->GetPointLocation(entry); loc->IncRef(); PPoint new_entry = func_cfg->AddPoint(loc); PEdge *skip_edge = PEdge::MakeSkip(new_entry, entry); func_cfg->AddEdge(skip_edge); func_cfg->SetEntryPoint(new_entry); // setup the tables we need to do loop splitting. SetupTables(); // compute the points reachable from the entry point. GetEntryReachable(func_cfg); // the real loops in the program with back edges. Vector<PPoint> loops; for (size_t lind = 0; lind < func_cfg->GetLoopHeadCount(); lind++) { PPoint head = func_cfg->GetLoopHead(lind).point; if (GetLoopBackedges(func_cfg, head)) loops.PushBack(head); } // compute reachability and check for irreducible loops. for (size_t lind = 0; lind < func_cfg->GetLoopHeadCount(); lind++) { const LoopHead &head = func_cfg->GetLoopHead(lind); if (GetLoopReachable(func_cfg, head.point)) { // loop is irreducible. // get the loop's irreducible edges. Vector<PEdge*> irreducible_edges; GetLoopBody(func_cfg, head.point, &irreducible_edges); Assert(!irreducible_edges.Empty()); // clone the loop's body and remove the irreducible edges. ReduceLoop(func_cfg, head.point, irreducible_edges); // try again on the modified CFG. CleanupTables(); SplitLoops(func_cfg, result_cfg_list); return; } } // there are no irreducible loops at this point so this should // never have any entries added. Vector<PEdge*> irreducible_edges; // compute loop bodies. for (size_t lind = 0; lind < loops.Size(); lind++) { PPoint head = loops[lind]; GetLoopBody(func_cfg, head, &irreducible_edges); Assert(irreducible_edges.Empty()); } // construct a tree of all the loops. loop A contains loop B // if A != B and the head of B is in the body of A. PPointListHash loop_tree; // split off all the loops in the CFG. make sure we split inner loops // before outer, so that the Loop edges on inner loops will appear in // the split body for outer loops. while (!loops.Empty()) { // find a candidate loop to split. this is one whose loop children // have already been split off and are no longer in the loops list. PPoint loophead = 0; for (size_t lind = 0; lind < loops.Size(); lind++) { bool is_viable = true; for (size_t xlind = 0; xlind < loops.Size(); xlind++) { if (xlind == lind) continue; Assert(loops[lind] != loops[xlind]); if (body_table->Lookup(PPointPair(loops[lind], loops[xlind]))) { is_viable = false; break; } } if (is_viable) { loophead = loops[lind]; loops[lind] = loops.Back(); loops.PopBack(); break; } } Assert(loophead); BlockCFG *loop_cfg = SplitSingleLoop(loophead, loops, func_cfg); result_cfg_list->PushBack(loop_cfg); } // clear out the loopheads, we don't want them around anymore. func_cfg->ClearLoopHeads(); // trim unreachable points in the function CFG (i.e. bodies of loops that // now redirect to point zero), collapse skips and topo sort. TrimUnreachable(func_cfg, true); TopoSortCFG(func_cfg); result_cfg_list->PushBack(func_cfg); CleanupTables(); // fill in any loop parents for the inner loop CFGs, and make sure the // result CFGs are ordered correctly, with inner loops before outer loops // and the outer function. for (size_t cind = 0; cind < result_cfg_list->Size(); cind++) { BlockCFG *cfg = result_cfg_list->At(cind); for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) { if (PEdgeLoop *edge = cfg->GetEdge(eind)->IfLoop()) { BlockId *target_id = edge->GetLoopId(); bool found_target = false; for (size_t xcind = 0; xcind < cind; xcind++) { BlockCFG *xcfg = result_cfg_list->At(xcind); if (xcfg->GetId() == target_id) { found_target = true; cfg->GetId()->IncRef(); BlockPPoint where(cfg->GetId(), edge->GetSource()); xcfg->AddLoopParent(where); // mark the isomorphic points in the parent CFG. GetLoopIsomorphicPoints(cfg, edge, xcfg); break; } } Assert(found_target); } } } // assign the final names to the various loop CFGs. FillLoopNames(func_cfg, "loop", *result_cfg_list); }
TEST_F(BinderCorrectnessTest, SelectStatementTest) { SetupTables(); auto& parser = parser::PostgresParser::GetInstance(); catalog::Catalog* catalog_ptr = catalog::Catalog::GetInstance(); // Test regular table name LOG_INFO("Parsing sql query"); unique_ptr<binder::BindNodeVisitor> binder(new binder::BindNodeVisitor()); string selectSQL = "SELECT A.a1, B.b2 FROM A INNER JOIN b ON a.a1 = b.b1 " "WHERE a1 < 100 GROUP BY A.a1, B.b2 HAVING a1 > 50 " "ORDER BY a1"; auto parse_tree = parser.BuildParseTree(selectSQL); auto selectStmt = dynamic_cast<parser::SelectStatement*>(parse_tree->GetStatements().at(0)); binder->BindNameToNode(selectStmt); oid_t db_oid = catalog_ptr->GetDatabaseWithName(DEFAULT_DB_NAME)->GetOid(); oid_t tableA_oid = catalog_ptr->GetTableWithName(DEFAULT_DB_NAME, "a")->GetOid(); oid_t tableB_oid = catalog_ptr->GetTableWithName(DEFAULT_DB_NAME, "b")->GetOid(); // Check select_list LOG_INFO("Checking select list"); auto tupleExpr = (expression::TupleValueExpression*)(*selectStmt->select_list)[0]; EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableA_oid, 0)); // A.a1 EXPECT_EQ(type::TypeId::INTEGER, tupleExpr->GetValueType()); tupleExpr = (expression::TupleValueExpression*)(*selectStmt->select_list)[1]; EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableB_oid, 1)); // B.b2 EXPECT_EQ(type::TypeId::VARCHAR, tupleExpr->GetValueType()); // Check join condition LOG_INFO("Checking join condition"); tupleExpr = (expression::TupleValueExpression*) selectStmt->from_table->join->condition->GetChild(0); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableA_oid, 0)); // a.a1 tupleExpr = (expression::TupleValueExpression*) selectStmt->from_table->join->condition->GetChild(1); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableB_oid, 0)); // b.b1 // Check Where clause LOG_INFO("Checking where clause"); tupleExpr = (expression::TupleValueExpression*)selectStmt->where_clause->GetChild(0); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableA_oid, 0)); // a1 // Check Group By and Having LOG_INFO("Checking group by"); tupleExpr = (expression::TupleValueExpression*)selectStmt->group_by->columns->at(0); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableA_oid, 0)); // A.a1 tupleExpr = (expression::TupleValueExpression*)selectStmt->group_by->columns->at(1); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableB_oid, 1)); // B.b2 tupleExpr = (expression::TupleValueExpression*)selectStmt->group_by->having->GetChild( 0); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableA_oid, 0)); // a1 // Check Order By LOG_INFO("Checking order by"); tupleExpr = (expression::TupleValueExpression*)selectStmt->order->exprs->at(0); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableA_oid, 0)); // a1 // Check alias ambiguous LOG_INFO("Checking duplicate alias and table name."); binder.reset(new binder::BindNodeVisitor()); selectSQL = "SELECT * FROM A, B as A"; parse_tree = parser.BuildParseTree(selectSQL); selectStmt = (parser::SelectStatement*)(parse_tree->GetStatements().at(0)); try { binder->BindNameToNode(selectStmt); EXPECT_TRUE(false); } catch (Exception& e) { LOG_INFO("Correct! Exception(%s) catched", e.what()); } // Test select from different table instances from the same physical schema binder.reset(new binder::BindNodeVisitor()); selectSQL = "SELECT * FROM A, A as AA where A.a1 = AA.a2"; parse_tree = parser.BuildParseTree(selectSQL); selectStmt = (parser::SelectStatement*)(parse_tree->GetStatements().at(0)); binder->BindNameToNode(selectStmt); LOG_INFO("Checking where clause"); tupleExpr = (expression::TupleValueExpression*)selectStmt->where_clause->GetChild(0); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableA_oid, 0)); // a1 tupleExpr = (expression::TupleValueExpression*)selectStmt->where_clause->GetChild(1); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableA_oid, 1)); // a1 // Test alias and select_list LOG_INFO("Checking select_list and table alias binding"); binder.reset(new binder::BindNodeVisitor()); selectSQL = "SELECT AA.a1, b2 FROM A as AA, B WHERE AA.a1 = B.b1"; parse_tree = parser.BuildParseTree(selectSQL); selectStmt = (parser::SelectStatement*)(parse_tree->GetStatements().at(0)); binder->BindNameToNode(selectStmt); tupleExpr = (expression::TupleValueExpression*)(selectStmt->select_list->at(0)); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableA_oid, 0)); tupleExpr = (expression::TupleValueExpression*)(selectStmt->select_list->at(1)); EXPECT_EQ(tupleExpr->GetBoundOid(), make_tuple(db_oid, tableB_oid, 1)); // Delete the test database auto& txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); catalog_ptr->DropDatabaseWithName(DEFAULT_DB_NAME, txn); txn_manager.CommitTransaction(txn); }