77731221创建于 3月23日历史提交
/*
 * Copyright (c) 2026 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

#include <gtest/gtest.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <algorithm>
#include <ctime>
#include <sstream>
#include <string>
#include <vector>

#include "abs_predicates.h"
#include "rdb_test_common.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
#include "rdb_predicates.h"

using namespace testing::ext;
using namespace OHOS::NativeRdb;

constexpr int CYCLENUM = 13;

class RdbStorePredicateJoinBTest : public testing::Test {
public:
    static void SetUpTestCase(void);
    static void TearDownTestCase(void);
    void SetUp();
    void TearDown();
    void GenerateAllTables();
    void InsertDeptDates();
    void InsertJobDates();
    void InsertEmpDates();
    void InsertSalarygradeDates();
    int ResultSize(std::shared_ptr<ResultSet> &resultSet);

    static const std::string DATABASE_NAME;

protected:
    std::shared_ptr<RdbStore> store_;
};

const std::string RdbStorePredicateJoinBTest::DATABASE_NAME = RDB_TEST_PATH + "predicates_join_b_test.db";

const std::string CREATE_TABLE_DEPT_SQL =
    std::string("CREATE TABLE IF NOT EXISTS dept ") + std::string("(id INTEGER PRIMARY KEY , dName TEXT , loc TEXT)");
const std::string CREATE_TABLE_JOB_SQL = std::string("CREATE TABLE IF NOT EXISTS job ") +
                                         std::string("(id INTEGER PRIMARY KEY , jName TEXT , description TEXT)");
const std::string CREATE_TABLE_EMP_SQL =
    std::string("CREATE TABLE IF NOT EXISTS emp ") +
    std::string("(id INTEGER PRIMARY KEY ,eName TEXT, jobId INTEGER , ") +
    std::string("mgr INTEGER, joinDate TEXT, salary REAL, bonus REAL, deptId INTEGER,") +
    std::string("FOREIGN KEY (jobId) REFERENCES job (id) ON UPDATE NO ACTION ON DELETE CASCADE,") +
    std::string("FOREIGN KEY (deptId) REFERENCES dept (id) ON UPDATE NO ACTION ON DELETE CASCADE)");
const std::string CREATE_TABLE_SALARYGRADE_SQL =
    std::string("CREATE TABLE IF NOT EXISTS salarygrade") +
    std::string("(grade INTEGER PRIMARY KEY,loSalary INTEGER, hiSalary INTEGER)");

class PredicateJoinBTestOpenCallback : public RdbOpenCallback {
public:
    int OnCreate(RdbStore &store) override;
    int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override;
};

int PredicateJoinBTestOpenCallback::OnCreate(RdbStore &store)
{
    return E_OK;
}

int PredicateJoinBTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
{
    return E_OK;
}

void RdbStorePredicateJoinBTest::SetUpTestCase(void)
{
    RdbHelper::DeleteRdbStore(RdbStorePredicateJoinBTest::DATABASE_NAME);
}

void RdbStorePredicateJoinBTest::TearDownTestCase(void)
{
}

void RdbStorePredicateJoinBTest::SetUp(void)
{
    store_ = nullptr;
    RdbHelper::DeleteRdbStore(RdbStorePredicateJoinBTest::DATABASE_NAME);
    int errCode = E_OK;
    RdbStoreConfig config(RdbStorePredicateJoinBTest::DATABASE_NAME);
    PredicateJoinBTestOpenCallback helper;
    store_ = RdbHelper::GetRdbStore(config, 1, helper, errCode);
    EXPECT_NE(store_, nullptr);
    RdbStorePredicateJoinBTest::GenerateAllTables();
}

void RdbStorePredicateJoinBTest::TearDown(void)
{
    store_ = nullptr;
    RdbHelper::DeleteRdbStore(RdbStorePredicateJoinBTest::DATABASE_NAME);
}

void RdbStorePredicateJoinBTest::GenerateAllTables()
{
    store_->ExecuteSql(CREATE_TABLE_DEPT_SQL);
    RdbStorePredicateJoinBTest::InsertDeptDates();

    store_->ExecuteSql(CREATE_TABLE_JOB_SQL);
    RdbStorePredicateJoinBTest::InsertJobDates();

    store_->ExecuteSql(CREATE_TABLE_EMP_SQL);
    RdbStorePredicateJoinBTest::InsertEmpDates();

    store_->ExecuteSql(CREATE_TABLE_SALARYGRADE_SQL);
    RdbStorePredicateJoinBTest::InsertSalarygradeDates();
}

void RdbStorePredicateJoinBTest::InsertDeptDates()
{
    int64_t id;
    ValuesBucket values;

    values.PutInt("id", 10);
    values.PutString("dName", std::string("JiaoYanBU"));
    values.PutString("loc", std::string("BeiJing"));
    store_->Insert(id, "dept", values);

    values.Clear();
    values.PutInt("id", 20);
    values.PutString("dName", std::string("XueGongBu"));
    values.PutString("loc", std::string("ShangHai"));
    store_->Insert(id, "dept", values);

    values.Clear();
    values.PutInt("id", 30);
    values.PutString("dName", std::string("XiaoShouBu"));
    values.PutString("loc", std::string("GuangZhou"));
    store_->Insert(id, "dept", values);

    values.Clear();
    values.PutInt("id", 40);
    values.PutString("dName", std::string("CaiWuBu"));
    values.PutString("loc", std::string("ShenZhen"));
    store_->Insert(id, "dept", values);
}

void RdbStorePredicateJoinBTest::InsertJobDates()
{
    int64_t id;
    ValuesBucket values;

    values.PutInt("id", 1);
    values.PutString("jName", std::string("Chairman"));
    values.PutString("description", std::string("ManageTheEntireCompany"));
    store_->Insert(id, "job", values);

    values.Clear();
    values.PutInt("id", 2);
    values.PutString("jName", std::string("Manager"));
    values.PutString("description", std::string("ManageEmployeesOfTheDepartment"));
    store_->Insert(id, "job", values);

    values.Clear();
    values.PutInt("id", 3);
    values.PutString("jName", std::string("Salesperson"));
    values.PutString("description", std::string("SellingProductsToCustomers"));
    store_->Insert(id, "job", values);

    values.Clear();
    values.PutInt("id", 4);
    values.PutString("jName", std::string("Clerk"));
    values.PutString("description", std::string("UseOfficeSoftware"));
    store_->Insert(id, "job", values);
}

void RdbStorePredicateJoinBTest::InsertEmpDates()
{
    int64_t id;

    int ret = 0;
    for (int i = 0; i <= CYCLENUM; i++) {
        ret = store_->Insert(id, "emp", RdbTestUtils::SetRowDatas(RdbTestUtils::g_RowDatas[i]));
    }
    EXPECT_EQ(ret, E_OK);
}

void RdbStorePredicateJoinBTest::InsertSalarygradeDates()
{
    int64_t id;
    ValuesBucket values;

    values.PutInt("grade", 1);
    values.PutInt("loSalary", 7000);
    values.PutInt("hiSalary", 12000);
    store_->Insert(id, "salarygrade", values);

    values.Clear();
    values.PutInt("grade", 2);
    values.PutInt("loSalary", 12010);
    values.PutInt("hiSalary", 14000);
    store_->Insert(id, "salarygrade", values);

    values.Clear();
    values.PutInt("grade", 3);
    values.PutInt("loSalary", 14010);
    values.PutInt("hiSalary", 20000);
    store_->Insert(id, "salarygrade", values);

    values.Clear();
    values.PutInt("grade", 4);
    values.PutInt("loSalary", 20010);
    values.PutInt("hiSalary", 30000);
    store_->Insert(id, "salarygrade", values);

    values.Clear();
    values.PutInt("grade", 5);
    values.PutInt("loSalary", 30010);
    values.PutInt("hiSalary", 99990);
    store_->Insert(id, "salarygrade", values);
}

int RdbStorePredicateJoinBTest::ResultSize(std::shared_ptr<ResultSet> &resultSet)
{
    if (resultSet->GoToFirstRow() != E_OK) {
        return 0;
    }
    int count;
    resultSet->GetRowCount(count);
    return count;
}

/* *
 * @tc.name: RdbStore_InnerJoinB_001
 * @tc.desc: Normal testCase of RdbPredicates for CrossJoin
 * @tc.type: FUNC
 */
HWTEST_F(RdbStorePredicateJoinBTest, RdbStore_CrossJoinB_001, TestSize.Level1)
{
    RdbPredicates predicates("emp");

    std::vector<std::string> clauses;
    clauses.push_back("emp.deptId = dept.id");
    predicates.CrossJoin("dept")->On(clauses);

    std::vector<std::string> joinTypes;
    joinTypes.push_back("CROSS JOIN");

    EXPECT_EQ(joinTypes, predicates.GetJoinTypes());
    EXPECT_EQ("dept", predicates.GetJoinTableNames()[0]);
    EXPECT_EQ("ON(emp.deptId = dept.id)", predicates.GetJoinConditions()[0]);
    EXPECT_EQ("CROSS JOIN dept ON(emp.deptId = dept.id)", predicates.GetJoinClause());

    std::vector<std::string> columns;
    std::shared_ptr<ResultSet> allDataTypes = store_->Query(predicates, columns);
    EXPECT_EQ(14, ResultSize(allDataTypes));

    EXPECT_EQ(E_OK, allDataTypes->GoToFirstRow());

    int id;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(0, id));
    EXPECT_EQ(1001, id);

    std::string eName;
    EXPECT_EQ(E_OK, allDataTypes->GetString(1, eName));
    EXPECT_EQ("SunWuKong", eName);

    int jobId;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(2, jobId));
    EXPECT_EQ(4, jobId);

    int mgr;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(3, mgr));
    EXPECT_EQ(1004, mgr);

    std::string joinDate;
    EXPECT_EQ(E_OK, allDataTypes->GetString(4, joinDate));
    EXPECT_EQ("2000-12-17", joinDate);

    double salary;
    EXPECT_EQ(E_OK, allDataTypes->GetDouble(5, salary));
    EXPECT_EQ(8000.00, salary);

    bool bonus;
    EXPECT_EQ(E_OK, allDataTypes->IsColumnNull(6, bonus));
    EXPECT_EQ(true, bonus);

    int deptId;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(7, deptId));
    EXPECT_EQ(20, deptId);

    int id_1;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(8, id_1));
    EXPECT_EQ(20, id_1);

    std::string dName;
    EXPECT_EQ(E_OK, allDataTypes->GetString(9, dName));
    EXPECT_EQ("XueGongBu", dName);

    std::string loc;
    EXPECT_EQ(E_OK, allDataTypes->GetString(10, loc));
    EXPECT_EQ("ShangHai", loc);
}

/* *
 * @tc.name: RdbStore_InnerJoinB_002
 * @tc.desc: Normal testCase of RdbPredicates for InnerJoin
 * @tc.type: FUNC
 */
HWTEST_F(RdbStorePredicateJoinBTest, RdbStore_InnerJoinB_002, TestSize.Level1)
{
    RdbPredicates predicates("emp t1");

    std::vector<std::string> clauses;
    clauses.push_back("t1.jobId = t2.id");
    predicates.InnerJoin("job t2")->On(clauses)->EqualTo("t1.eName", "SunWuKong");

    std::vector<std::string> joinTypes;
    joinTypes.push_back("INNER JOIN");
    EXPECT_EQ(joinTypes, predicates.GetJoinTypes());
    EXPECT_EQ("ON(t1.jobId = t2.id)", predicates.GetJoinConditions()[0]);

    std::vector<std::string> columns;
    columns.push_back("t1.id");
    columns.push_back("t1.eName");
    columns.push_back("t1.salary");
    columns.push_back("t2.jName");
    columns.push_back("t2.description");
    std::shared_ptr<ResultSet> allDataTypes = store_->Query(predicates, columns);
    EXPECT_EQ(1, ResultSize(allDataTypes));
    EXPECT_EQ(E_OK, allDataTypes->GoToFirstRow());

    int id;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(0, id));
    EXPECT_EQ(1001, id);

    std::string eName;
    EXPECT_EQ(E_OK, allDataTypes->GetString(1, eName));
    EXPECT_EQ("SunWuKong", eName);

    double salary;
    EXPECT_EQ(E_OK, allDataTypes->GetDouble(2, salary));
    EXPECT_EQ(8000.00, salary);

    std::string jName;
    EXPECT_EQ(E_OK, allDataTypes->GetString(3, jName));
    EXPECT_EQ("Clerk", jName);

    std::string description;
    EXPECT_EQ(E_OK, allDataTypes->GetString(4, description));
    EXPECT_EQ("UseOfficeSoftware", description);
}

/* *
 * @tc.name: RdbStore_InnerJoinB_003
 * @tc.desc: Normal testCase of RdbPredicates for InnerJoin
 * @tc.type: FUNC
 */
HWTEST_F(RdbStorePredicateJoinBTest, RdbStore_InnerJoinB_003, TestSize.Level1)
{
    RdbPredicates predicates("emp t1");

    std::vector<std::string> clauses;
    clauses.push_back("t1.salary BETWEEN t2.losalary AND t2.hisalary");
    predicates.InnerJoin("salarygrade t2")->On(clauses);

    std::vector<std::string> joinTypes;
    joinTypes.push_back("INNER JOIN");
    EXPECT_EQ(joinTypes, predicates.GetJoinTypes());

    std::vector<std::string> columns;
    columns.push_back("t1.eName");
    columns.push_back("t1.salary");
    columns.push_back("t2.*");
    std::shared_ptr<ResultSet> allDataTypes = store_->Query(predicates, columns);
    EXPECT_EQ(14, ResultSize(allDataTypes));
    EXPECT_EQ(E_OK, allDataTypes->GoToFirstRow());

    std::string eName;
    EXPECT_EQ(E_OK, allDataTypes->GetString(0, eName));
    EXPECT_EQ("SunWuKong", eName);

    double salary;
    EXPECT_EQ(E_OK, allDataTypes->GetDouble(1, salary));
    EXPECT_EQ(8000.00, salary);

    int grade;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(2, grade));
    EXPECT_EQ(1, grade);

    int loSalary;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(3, loSalary));
    EXPECT_EQ(7000, loSalary);

    int hiSalary;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(4, hiSalary));
    EXPECT_EQ(12000, hiSalary);
}

/* *
 * @tc.name: RdbStore_InnerJoinB_004
 * @tc.desc: Normal testCase of RdbPredicates for InnerJoin
 * @tc.type: FUNC
 */
HWTEST_F(RdbStorePredicateJoinBTest, RdbStore_InnerJoinB_004, TestSize.Level1)
{
    RdbPredicates predicates("emp t1");

    std::vector<std::string> clauses;
    clauses.push_back("t1.jobId = t2.id");
    clauses.push_back("t1.deptId = t3.id");
    clauses.push_back("t1.salary BETWEEN t4.losalary AND t4.hisalary");
    predicates.InnerJoin("job t2")->InnerJoin("dept t3")->InnerJoin("salarygrade t4")->On(clauses);

    std::vector<std::string> joinTypes;
    joinTypes.push_back("INNER JOIN");
    joinTypes.push_back("INNER JOIN");
    joinTypes.push_back("INNER JOIN");
    EXPECT_EQ(joinTypes, predicates.GetJoinTypes());
    EXPECT_EQ("", predicates.GetJoinConditions()[0]);
    EXPECT_EQ("", predicates.GetJoinConditions()[1]);
    EXPECT_EQ("ON(t1.jobId = t2.id AND t1.deptId = t3.id AND t1.salary BETWEEN "
              "t4.losalary AND t4.hisalary)",
        predicates.GetJoinConditions()[2]);

    std::vector<std::string> columns;
    columns.push_back("t1.eName");
    columns.push_back("t1.salary");
    columns.push_back("t2.jName");
    columns.push_back("t2.description");
    columns.push_back("t3.dName");
    columns.push_back("t3.loc");
    columns.push_back("t4.grade");
    std::shared_ptr<ResultSet> allDataTypes = store_->Query(predicates, columns);
    EXPECT_EQ(14, ResultSize(allDataTypes));
    EXPECT_EQ(E_OK, allDataTypes->GoToFirstRow());

    std::string eName;
    EXPECT_EQ(E_OK, allDataTypes->GetString(0, eName));
    EXPECT_EQ("SunWuKong", eName);

    double salary;
    EXPECT_EQ(E_OK, allDataTypes->GetDouble(1, salary));
    EXPECT_EQ(8000.00, salary);

    std::string jName;
    EXPECT_EQ(E_OK, allDataTypes->GetString(2, jName));
    EXPECT_EQ("Clerk", jName);

    std::string description;
    EXPECT_EQ(E_OK, allDataTypes->GetString(3, description));
    EXPECT_EQ("UseOfficeSoftware", description);

    std::string dName;
    EXPECT_EQ(E_OK, allDataTypes->GetString(4, dName));
    EXPECT_EQ("XueGongBu", dName);

    std::string loc;
    EXPECT_EQ(E_OK, allDataTypes->GetString(5, loc));
    EXPECT_EQ("ShangHai", loc);

    int grade;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(6, grade));
    EXPECT_EQ(1, grade);
}

/* *
 * @tc.name: RdbStore_LeftOuterJoinB_005
 * @tc.desc: Normal testCase of RdbPredicates for LeftOuterJoin
 * @tc.type: FUNC
 */
HWTEST_F(RdbStorePredicateJoinBTest, RdbStore_LeftOuterJoinB_005, TestSize.Level1)
{
    RdbPredicates predicates("emp t1");

    std::vector<std::string> clauses;
    clauses.push_back("t1.mgr = t2.id");
    std::vector<std::string> joinTypes;
    joinTypes.push_back("LEFT OUTER JOIN");

    predicates.LeftOuterJoin("emp t2")->On(clauses);
    EXPECT_EQ(joinTypes, predicates.GetJoinTypes());
    EXPECT_EQ("ON(t1.mgr = t2.id)", predicates.GetJoinConditions()[0]);

    std::vector<std::string> columns;
    columns.push_back("t1.eName");
    columns.push_back("t1.mgr");
    columns.push_back("t2.id");
    columns.push_back("t2.eName");
    std::shared_ptr<ResultSet> allDataTypes = store_->Query(predicates, columns);
    EXPECT_EQ(14, ResultSize(allDataTypes));
    EXPECT_EQ(E_OK, allDataTypes->GoToFirstRow());

    std::string eName;
    EXPECT_EQ(E_OK, allDataTypes->GetString(0, eName));
    EXPECT_EQ("SunWuKong", eName);

    int mgr;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(1, mgr));
    EXPECT_EQ(1004, mgr);

    int id;
    EXPECT_EQ(E_OK, allDataTypes->GetInt(2, id));
    EXPECT_EQ(1004, id);

    std::string eName_1;
    EXPECT_EQ(E_OK, allDataTypes->GetString(3, eName_1));
    EXPECT_EQ("TangCeng", eName_1);
}