/* 
 * Copyright (c) 2011, 2012,Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#include "tut_stdafx.h"

#include "testgrt.h"
#include "grt_test_utility.h"
#include "grt/grt_manager.h"
#include "grtpp.h"
#include "synthetic_mysql_model.h"
#include "grtdb/diff_dbobjectmatch.h"
#include "interfaces/sqlgenerator.h"
#include "wb_mysql_import.h"

#include "modules/db.mysql/src/db_mysql_diffsqlgen.h"

BEGIN_TEST_DATA_CLASS(sql_generation)
protected:
    WBTester tester;
    WbMysqlImportImpl *wb_mysql_import_module;
    SQLGeneratorInterfaceImpl *diffsql_module;
    sql::ConnectionWrapper connection;
    TEST_DATA_CONSTRUCTOR(sql_generation)
    {
        wb_mysql_import_module= NULL;
        diffsql_module= NULL;

        // load modules
        wb_mysql_import_module= tester.grt->get_native_module<WbMysqlImportImpl>();
        ensure("WBModuleImport module initialization", NULL != wb_mysql_import_module);
        diffsql_module = dynamic_cast<SQLGeneratorInterfaceImpl*>(tester.grt->get_module("DbMySQL"));
        ensure("DiffSQLGen module initialization", NULL != diffsql_module);

        // init datatypes
        populate_grt(tester.grt, NULL, tester);

        // init database connection
        connection = tester.create_connection_for_import();
    }

END_TEST_DATA_CLASS

TEST_MODULE(sql_generation, "sql generation");

//Test if sql generated for syntetic model is valid
TEST_FUNCTION(1)
{
    grt::ValueRef e;
    std::auto_ptr<sql::Statement> stmt(connection->createStatement());
    NormalizedComparer cmp(tester.grt);
    grt::DbObjectMatchAlterOmf omf;

    SynteticMySQLModel model(tester.grt);
    db_mysql_ViewRef view(tester.grt);
    model.schema->views().insert(view);       view->owner(model.schema);
    view->name("v2");
    view->sqlDefinition("create view v2 as SELECT "
        "if(t1.id > 2, 'active, very active', 'inactive, very very very inactive'), "
        "if(t1.id > 4, 'active, very active', 'inactive, very very very inactive') "
            "FROM t1");

    db_mysql_CatalogRef catalog = model.catalog;
    
    cmp.init_omf(&omf);

    boost::shared_ptr<DiffChange> create_change= diff_make(e, catalog, &omf);
    boost::shared_ptr<DiffChange> drop_change= diff_make(catalog, e, &omf);

    DictRef create_map(tester.grt);
    DictRef drop_map(tester.grt);
    grt::DictRef options(tester.grt);
    options.set("UseFilteredLists", grt::IntegerRef(0));
    options.set("OutputContainer", create_map);
    options.set("CaseSensitive", grt::IntegerRef(omf.case_sensitive));
    options.set("GenerateSchemaDrops", grt::IntegerRef(1));
    options.set("GenerateDrops", grt::IntegerRef(1));
    diffsql_module->generateSQL(catalog, options, create_change);

    options.set("OutputContainer", drop_map);
    diffsql_module->generateSQL(catalog, options, drop_change);

    diffsql_module->makeSQLExportScript(catalog, options, create_map, drop_map);
    std::string export_sql_script= options.get_string("OutputScript");
    ensure("DROP TABLE missing in generated sql",export_sql_script.find("DROP TABLE IF EXISTS `test_schema`.`t1`") != std::string::npos);
    execute_script(stmt.get(), export_sql_script,tester.wb->get_grt_manager());
}

//Forward engeneer syntetic model without qualifing schema, but inserting USE statements instead
TEST_FUNCTION(2)
{
    grt::ValueRef e;
    std::auto_ptr<sql::Statement> stmt(connection->createStatement());
    NormalizedComparer cmp(tester.grt);
    grt::DbObjectMatchAlterOmf omf;

    SynteticMySQLModel model(tester.grt);

    db_mysql_CatalogRef catalog = model.catalog;
    
    cmp.init_omf(&omf);

    boost::shared_ptr<DiffChange> create_change= diff_make(e, catalog, &omf);
    boost::shared_ptr<DiffChange> drop_change= diff_make(catalog, e, &omf);

    DictRef create_map(tester.grt);
    DictRef drop_map(tester.grt);
    grt::DictRef options(tester.grt);
    options.set("UseFilteredLists", grt::IntegerRef(0));
    options.set("OutputContainer", create_map);
    options.set("CaseSensitive", grt::IntegerRef(omf.case_sensitive));
    options.set("GenerateSchemaDrops", grt::IntegerRef(1));
    options.set("UseShortNames", grt::IntegerRef(1));
    options.set("GenerateUse", grt::IntegerRef(1));
    options.set("GenerateDrops", grt::IntegerRef(1));
    diffsql_module->generateSQL(catalog, options, create_change);

    options.set("OutputContainer", drop_map);
    diffsql_module->generateSQL(catalog, options, drop_change);

    diffsql_module->makeSQLExportScript(catalog, options, create_map, drop_map);
    std::string export_sql_script= options.get_string("OutputScript");
    execute_script(stmt.get(), export_sql_script,tester.wb->get_grt_manager());
}

//Test case for Bug #11926862 NO WAY TO SORT SCHEMAS ON EXPORT
TEST_FUNCTION(3)
{
    grt::ValueRef e;
    std::auto_ptr<sql::Statement> stmt(connection->createStatement());
    NormalizedComparer cmp(tester.grt);
    grt::DbObjectMatchAlterOmf omf;

    tester.wb->open_document("data/workbench/11926862.mwb");
    db_mysql_CatalogRef catalog = db_mysql_CatalogRef::cast_from(tester.wb->get_document()->physicalModels().get(0)->catalog());
    
    cmp.init_omf(&omf);

    boost::shared_ptr<DiffChange> create_change= diff_make(e, catalog, &omf);
    boost::shared_ptr<DiffChange> drop_change= diff_make(catalog, e, &omf);

    DictRef create_map(tester.grt);
    DictRef drop_map(tester.grt);
    grt::DictRef options(tester.grt);
    options.set("UseFilteredLists", grt::IntegerRef(0));
    options.set("OutputContainer", create_map);
    options.set("CaseSensitive", grt::IntegerRef(omf.case_sensitive));
    options.set("GenerateSchemaDrops", grt::IntegerRef(1));
    options.set("UseShortNames", grt::IntegerRef(1));
    options.set("GenerateUse", grt::IntegerRef(1));
    options.set("GenerateDrops", grt::IntegerRef(1));
    diffsql_module->generateSQL(catalog, options, create_change);

    options.set("OutputContainer", drop_map);
    diffsql_module->generateSQL(catalog, options, drop_change);

    diffsql_module->makeSQLExportScript(catalog, options, create_map, drop_map);
    std::string export_sql_script= options.get_string("OutputScript");
    execute_script(stmt.get(), export_sql_script,tester.wb->get_grt_manager());
}

//Test case for Bug #14278043 DB SYNCRONIZE MODEL GENERATES INCORRECT COLLATION
//If somehow collation doesn't correspond to charset it should be skipped during 
//sql generation to create valid DDL
TEST_FUNCTION(4)
{
    grt::ValueRef e;
    std::auto_ptr<sql::Statement> stmt(connection->createStatement());
    NormalizedComparer cmp(tester.grt);
    grt::DbObjectMatchAlterOmf omf;

    SynteticMySQLModel model(tester.grt);
    
    model.schema->defaultCharacterSetName("utf8");
    model.schema->defaultCollationName("latin_1_sweidish_ci");
    model.table->defaultCharacterSetName("utf8");
    model.table->defaultCollationName("latin_1_sweidish_ci");
    model.columnText->characterSetName("utf8");
    model.columnText->collationName("latin_1_sweidish_ci");

    db_mysql_CatalogRef catalog = model.catalog;
    
    cmp.init_omf(&omf);

    boost::shared_ptr<DiffChange> create_change= diff_make(e, catalog, &omf);
    boost::shared_ptr<DiffChange> drop_change= diff_make(catalog, e, &omf);

    DictRef create_map(tester.grt);
    DictRef drop_map(tester.grt);
    grt::DictRef options(tester.grt);
    options.set("UseFilteredLists", grt::IntegerRef(0));
    options.set("OutputContainer", create_map);
    options.set("CaseSensitive", grt::IntegerRef(omf.case_sensitive));
    options.set("GenerateSchemaDrops", grt::IntegerRef(1));
    options.set("GenerateDrops", grt::IntegerRef(1));
    diffsql_module->generateSQL(catalog, options, create_change);

    options.set("OutputContainer", drop_map);
    diffsql_module->generateSQL(catalog, options, drop_change);

    diffsql_module->makeSQLExportScript(catalog, options, create_map, drop_map);
    std::string export_sql_script= options.get_string("OutputScript");
    execute_script(stmt.get(), export_sql_script,tester.wb->get_grt_manager());
}

END_TESTS
