/* 
 * Copyright (c) 2011, 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 "grts/structs.db.query.h"
#include "sqlide/wb_context_sqlide.h"
#include "sqlide/wb_live_schema_tree.h"

#include "grtpp.h"

#include "cppdbc.h"
#include "wb_helpers.h"
#include "cppconn/driver.h"
#include "cppconn/sqlstring.h"
#include "driver/mysql_driver.h"

#include "sqlide/wb_sql_editor_form.h"


using namespace grt;
using namespace wb;
using namespace sql;
using namespace sql::mysql;

/* This class is a friend of the Db_sql_editor on DEBUG mode, 
   this way everything is available for testing */
class Db_sql_editor_tester
{
public:
  void set_target(const Db_sql_editor::Ref& sql_editor)
  {
    db_sql_editor = sql_editor;
    db_sql_editor->_schema_tree->tree_changed_signal()->disconnect_all_slots();
  }

  void fetch_column_data(const std::string &schema_name, const std::string &obj_name, wb::LiveSchemaTree::ViewNode& view_node)
  {
    db_sql_editor->fetch_column_data(schema_name, obj_name, view_node);
  }

  void fetch_index_data(const std::string &schema_name, const std::string &obj_name, wb::LiveSchemaTree::TableNode& table_node)
  {
    db_sql_editor->fetch_index_data(schema_name, obj_name, table_node);
  }

  void fetch_trigger_data(const std::string &schema_name, const std::string &obj_name, wb::LiveSchemaTree::TableNode& table_node)
  {
    db_sql_editor->fetch_trigger_data(schema_name, obj_name, table_node);
  }

  void fetch_foreign_key_data(const std::string &schema_name, const std::string &obj_name, wb::LiveSchemaTree::TableNode& table_node)
  {
    db_sql_editor->fetch_foreign_key_data(schema_name, obj_name, table_node);
  }

  void load_schema_list()
  {
    return db_sql_editor->_schema_tree->refresh_ex(true);
  }

  void load_schema_data(const std::string& schema )
  {
    bec::NodeId schema_node = db_sql_editor->_schema_tree->get_node_for_object(schema, LiveSchemaTree::Schema, "");
    db_sql_editor->_schema_tree->expand_node(schema_node);
  }

  bool is_editable_select(const std::string &sql, std::string& schema_name, std::string& table_name, std::string& error)
  {
    return db_sql_editor->is_editable_select(sql, schema_name, table_name, error);
  }

  void exec_sql(std::string &sql)
  {
    return db_sql_editor->exec_sql(sql, Sql_editor::Ref(), true, false, false);
  }

private:
  Db_sql_editor::Ref db_sql_editor;


};

BEGIN_TEST_DATA_CLASS(wb_sql_editor_form_test)
public:
  WBTester tester;
  WBContextSQLIDE wb_context_sqlide;
  sql::ConnectionWrapper connection;
  Db_sql_editor::Ref db_sql_editor;
  Db_sql_editor_tester db_sql_editor_tester;
  GRT grt;

void populate_grt(GRT *grt, const char *rdbms_info_path)
{
  if(rdbms_info_path == NULL)
    rdbms_info_path= "../../bin/debug/modules/data/mysql_rdbms_info.xml";

  workbench_WorkbenchRef wb(grt);
  workbench_DocumentRef doc(grt);
  doc->owner(wb);
  wb->doc(doc);
  //grt->set("/wb", wb);

  db_mgmt_ManagementRef mgmt(grt); 
  wb->rdbmsMgmt(mgmt);
  mgmt->owner(wb);

  ListRef<db_DatatypeGroup> grouplist= 
    ListRef<db_DatatypeGroup>::cast_from(grt->unserialize("../../bin/debug/data/db_datatype_groups.xml"));

  db_mgmt_RdbmsRef rdbms= db_mgmt_RdbmsRef::cast_from(grt->unserialize(rdbms_info_path));
  ensure("db_mgmt_Rdbms initialization", rdbms.is_valid());
  grt->set("/rdbms", rdbms);

  mgmt->rdbms().insert(rdbms);
  rdbms->owner(mgmt);
}

void set_connection_properties(grt::GRT *grt, db_mgmt_ConnectionRef& connection)
{
  grt::DictRef conn_params(grt);
  conn_params.set("host", grt::StringRef(test_params->get_host_name()));
  conn_params.set("port", grt::IntegerRef(test_params->get_port()));
  conn_params.set("userName", grt::StringRef(test_params->get_user_name()));
  conn_params.set("password", grt::StringRef(test_params->get_password()));
  grt::replace_contents(connection->parameterValues(), conn_params);

  db_mgmt_DriverRef driverProperties= db_mgmt_DriverRef::cast_from(grt->get("/rdbms/drivers/0/"));
  connection->driver(driverProperties);
}

sql::ConnectionWrapper create_connection_for_import(grt::GRT *grt)
{
  // init database connection
  db_mgmt_ConnectionRef connectionProperties(grt);

  set_connection_properties(grt, connectionProperties);

  sql::DriverManager *dm= sql::DriverManager::getDriverManager();

  return dm->getConnection(connectionProperties);
}

TEST_DATA_CONSTRUCTOR(wb_sql_editor_form_test):wb_context_sqlide(tester.wbui)
{
  populate_grt(tester.grt, NULL);

  connection= create_connection_for_import(tester.grt);

  db_mgmt_ConnectionRef my_connection(tester.grt);
  set_connection_properties(tester.grt, my_connection);
  db_sql_editor = Db_sql_editor::create(&wb_context_sqlide, my_connection);
  db_sql_editor->connect();

  db_sql_editor_tester.set_target(db_sql_editor);

    //"USE `wb_sql_editor_form_test`;"
  static const char *sql1 =//
    "DROP DATABASE IF EXISTS `wb_sql_editor_form_test`;"
    "CREATE DATABASE IF NOT EXISTS `wb_sql_editor_form_test` DEFAULT CHARSET=latin1 DEFAULT COLLATE = latin1_swedish_ci;"

    "USE `wb_sql_editor_form_test`;"

    "CREATE TABLE language ("
      "language_id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,"
      "name CHAR(20) NOT NULL,"
      "last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,"
      "PRIMARY KEY (language_id)"
    ")ENGINE=InnoDB DEFAULT CHARSET=utf8;"

    "CREATE TABLE film ("
      "film_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,"
      "title VARCHAR(255) NOT NULL,"
      "description TEXT DEFAULT NULL,"
      "release_year YEAR DEFAULT NULL,"
      "language_id TINYINT UNSIGNED NOT NULL,"
      "original_language_id TINYINT UNSIGNED DEFAULT NULL,"
      "rental_duration TINYINT UNSIGNED NOT NULL DEFAULT 3,"
      "rental_rate DECIMAL(4,2) NOT NULL DEFAULT 4.99,"
      "length SMALLINT UNSIGNED DEFAULT NULL,"
      "replacement_cost DECIMAL(5,2) NOT NULL DEFAULT 19.99,"
      "rating ENUM('G','PG','PG-13','R','NC-17') DEFAULT 'G',"
      "special_features SET('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') DEFAULT NULL,"
      "last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,"
      "PRIMARY KEY  (film_id),"
      "KEY idx_title (title),"
      "KEY idx_fk_language_id (language_id),"
      "KEY idx_fk_original_language_id (original_language_id),"
      "CONSTRAINT fk_film_language FOREIGN KEY (language_id) REFERENCES language (language_id) ON DELETE RESTRICT ON UPDATE CASCADE,"
      "CONSTRAINT fk_film_language_original FOREIGN KEY (original_language_id) REFERENCES language (language_id) ON DELETE RESTRICT ON UPDATE CASCADE"
    ")ENGINE=InnoDB DEFAULT CHARSET=utf8;"

    "CREATE TABLE film_text ("
      "film_id SMALLINT NOT NULL,"
      "title VARCHAR(255) NOT NULL,"
      "description TEXT,"
      "PRIMARY KEY  (film_id),"
      "FULLTEXT KEY idx_title_description (title,description)"
    ")ENGINE=MyISAM DEFAULT CHARSET=utf8;"

    "CREATE TABLE complex_pk_table ("
      "dummy_first_id SMALLINT NOT NULL,"
      "dummy_second_id SMALLINT NOT NULL,"
      "title VARCHAR(255) NOT NULL,"
      "description TEXT,"
      "PRIMARY KEY  (dummy_first_id,dummy_second_id),"
      "FULLTEXT KEY idx_title_description (title,description)"
    ")ENGINE=MyISAM DEFAULT CHARSET=utf8;"

    "CREATE TABLE no_pk_table ("
      "dummy_id SMALLINT NOT NULL,"
      "title VARCHAR(255) NOT NULL,"
      "description TEXT,"
      "FULLTEXT KEY idx_title_description (title,description)"
    ")ENGINE=MyISAM DEFAULT CHARSET=utf8;"

    "CREATE TABLE pk_table_unique_not_null ("
      "dummy_pk SMALLINT NOT NULL,"
      "dummy_id SMALLINT NOT NULL,"
      "title VARCHAR(255) NOT NULL,"
      "description TEXT,"
      "FULLTEXT KEY idx_title_description (title,description),"
      "PRIMARY KEY  (dummy_pk),"
      "UNIQUE KEY dummy_id (dummy_id)"
    ")ENGINE=MyISAM DEFAULT CHARSET=utf8;"

    "CREATE TABLE no_pk_table_unique_not_null ("
      "dummy_id SMALLINT NOT NULL,"
      "title VARCHAR(255) NOT NULL,"
      "description TEXT,"
      "FULLTEXT KEY idx_title_description (title,description),"
      "UNIQUE KEY dummy_id (dummy_id)"
    ")ENGINE=MyISAM DEFAULT CHARSET=utf8;"

    "CREATE VIEW dummy_film_view"
    "AS"
    "SELECT film_id, title, description, release_year"
    "FROM film;"

  "DELIMITER ;;"
    "CREATE TRIGGER `ins_film` AFTER INSERT ON `film` FOR EACH ROW BEGIN"
        "INSERT INTO film_text (film_id, title, description)"
            "VALUES (new.film_id, new.title, new.description);"
      "END;;"


    "CREATE TRIGGER `upd_film` AFTER UPDATE ON `film` FOR EACH ROW BEGIN"
        "IF (old.title != new.title) or (old.description != new.description)"
        "THEN"
            "UPDATE film_text"
                "SET title=new.title,"
                    "description=new.description,"
                    "film_id=new.film_id"
            "WHERE film_id=old.film_id;"
        "END IF;"
      "END;;"


    "CREATE TRIGGER `del_film` AFTER DELETE ON `film` FOR EACH ROW BEGIN"
        "DELETE FROM film_text WHERE film_id = old.film_id;"
      "END;;"

    "DELIMITER ;";

  std::string sql(sql1);
  db_sql_editor_tester.exec_sql(sql);
//  std::auto_ptr<sql::Statement> stmt(connection->createStatement());
//  stmt->execute(sql1);

  db_sql_editor_tester.load_schema_list();
  db_sql_editor_tester.load_schema_data("wb_sql_editor_form_test");
 
}

END_TEST_DATA_CLASS;

TEST_MODULE(wb_sql_editor_form_test, "sql editor form test");


/* Testing for Db_sql_editor::fetch_column_data */
TEST_FUNCTION(1)
{
  wb::LiveSchemaTree::ViewNode test_node;

  /* Loads the column data from the film_text table */
  db_sql_editor_tester.fetch_column_data("wb_sql_editor_form_test", "language", test_node);

  ensure("Columns were not loaded", test_node.columns_loaded);
  ensure_equals("Unexpected column name", test_node.columns[0].name, "language_id");
  ensure("Unexpected primary key flag", test_node.columns[0].is_pk);
  ensure("Unexpected foreign key flag", !test_node.columns[0].is_fk);
  ensure_equals("Unexpected column name", test_node.columns[1].name, "name");
  ensure("Unexpected primary key flag", !test_node.columns[1].is_pk);
  ensure("Unexpected foreign key flag", !test_node.columns[1].is_fk);
  ensure_equals("Unexpected column name", test_node.columns[2].name, "last_update");
  ensure("Unexpected primary key flag", !test_node.columns[2].is_pk);
  ensure("Unexpected foreign key flag", !test_node.columns[2].is_fk);

  std::string details = "<b>Table:</b> "
                        "<font color='#148814'>"
	                        "<b>language</b>"
                        "</font>"
                        "<br>"
                        "<br>"
                        "<b>Columns:</b>"
                        "<table style=\"border: none; border-collapse: collapse;\">"
	                        "<tr>"
		                        "<td style=\"border:none; padding-left: 15px;\"><b><u>language_id</u></b></td>"
		                        "<td style=\"border:none; padding-left: 15px;\"><font color='#717171'>tinyint(3) UN PK AI</font></td>"
	                        "</tr>"
	                        "<tr>"
		                        "<td style=\"border:none; padding-left: 15px;\">name</td>"
		                        "<td style=\"border:none; padding-left: 15px;\"><font color='#717171'>char(20) </font></td>"
	                        "</tr>"
	                        "<tr>"
		                        "<td style=\"border:none; padding-left: 15px;\">last_update</td>"
		                        "<td style=\"border:none; padding-left: 15px;\"><font color='#717171'>timestamp </font></td>"
	                        "</tr>"
                        "</table>"
                        "<br>"
                        "<br>";



  ensure_equals("Unexpected details format", test_node.details, details);
}

/* Testing for Db_sql_editor::fetch_index_data */
TEST_FUNCTION(2)
{
  wb::LiveSchemaTree::TableNode test_node;

  /* Loads the index data for the film table */
  db_sql_editor_tester.fetch_index_data("wb_sql_editor_form_test", "film", test_node);

  ensure("Indexes were not loaded", test_node.indexes_loaded);
  ensure_equals("unexpected nuber of indexes", test_node.indexes.size(),4);

  ensure_equals("Unexpected index name", test_node.indexes[0].name, "PRIMARY");
  ensure("Unexpected non unique index found", test_node.indexes[0].unique);
  ensure_equals("Unexpected index type", test_node.indexes[0].type, 6);
  ensure_equals("Unexpected index column count", test_node.indexes[0].columns.size(), 1);
  ensure_equals("Unexpected index column name", test_node.indexes[0].columns[0].name, "film_id");
  ensure("Unexpected index column nullable value", !test_node.indexes[0].columns[0].nullable);

  ensure_equals("Unexpected index name", test_node.indexes[1].name, "idx_title");
  ensure("Unexpected unique index found", !test_node.indexes[1].unique);
  ensure_equals("Unexpected index type", test_node.indexes[1].type, 6);
  ensure_equals("Unexpected index column count", test_node.indexes[1].columns.size(), 1);
  ensure_equals("Unexpected index column name", test_node.indexes[1].columns[0].name, "title");
  ensure("Unexpected index column nullable value", !test_node.indexes[1].columns[0].nullable);

  ensure_equals("Unexpected index name", test_node.indexes[2].name, "idx_fk_language_id");
  ensure("Unexpected unique index found", !test_node.indexes[2].unique);
  ensure_equals("Unexpected index type", test_node.indexes[2].type, 6);
  ensure_equals("Unexpected index column count", test_node.indexes[2].columns.size(), 1);
  ensure_equals("Unexpected index column name", test_node.indexes[2].columns[0].name, "language_id");
  ensure("Unexpected index column nullable value", !test_node.indexes[2].columns[0].nullable);

  ensure_equals("Unexpected index name", test_node.indexes[3].name, "idx_fk_original_language_id");
  ensure("Unexpected unique index found", !test_node.indexes[3].unique);
  ensure_equals("Unexpected index type", test_node.indexes[3].type, 6);
  ensure_equals("Unexpected index column count", test_node.indexes[3].columns.size(), 1);
  ensure_equals("Unexpected index column name", test_node.indexes[3].columns[0].name, "original_language_id");
  ensure("Unexpected index column nullable value", test_node.indexes[3].columns[0].nullable);
}

/* Testing for Db_sql_editor::fetch_trigger_data */
TEST_FUNCTION(3)
{
  wb::LiveSchemaTree::TableNode test_node;

  /* Loads the trigger data for the film table */
  db_sql_editor_tester.fetch_trigger_data("wb_sql_editor_form_test", "film", test_node);

  //TODO : Add checks for the trigger data loading once the
  //       Trigger creation sql works

}

TEST_FUNCTION(4)
{
  wb::LiveSchemaTree::TableNode test_node;

  /* Loads the foreign key data for the film table */
  db_sql_editor_tester.fetch_foreign_key_data("wb_sql_editor_form_test", "film", test_node);

  ensure("Foreign Keys were not loaded", test_node.foreign_keys_loaded);

  ensure_equals("Unexpected foreign key name", test_node.foreign_keys[0].name, "fk_film_language");
  ensure_equals("Unexpected foreign key update rule", test_node.foreign_keys[0].update_rule, 1);
  ensure_equals("Unexpected foreign key delete rule", test_node.foreign_keys[0].delete_rule, 4);
  ensure_equals("Unexpected foreign key referenced table", test_node.foreign_keys[0].referenced_table, "language");
  ensure_equals("Unexpected foreign key referenced columns size", test_node.foreign_keys[0].columns.size(), 1);
  ensure_equals("Unexpected foreign key referencing column", test_node.foreign_keys[0].columns[0].name, "language_id");
  ensure_equals("Unexpected foreign key referenced column", test_node.foreign_keys[0].columns[0].referenced_column, "language_id");

  ensure_equals("Unexpected foreign key name", test_node.foreign_keys[1].name, "fk_film_language_original");
  ensure_equals("Unexpected foreign key update rule", test_node.foreign_keys[1].update_rule, 1);
  ensure_equals("Unexpected foreign key delete rule", test_node.foreign_keys[1].delete_rule, 4);
  ensure_equals("Unexpected foreign key referenced table", test_node.foreign_keys[1].referenced_table, "language");
  ensure_equals("Unexpected foreign key referenced columns size", test_node.foreign_keys[1].columns.size(), 1);
  ensure_equals("Unexpected foreign key referencing column", test_node.foreign_keys[1].columns[0].name, "original_language_id");
  ensure_equals("Unexpected foreign key referenced column", test_node.foreign_keys[1].columns[0].referenced_column, "language_id");
}

// Testing : Db_sql_editor::is_editable_select
TEST_FUNCTION(5)
{
  wb::LiveSchemaTree::TableNode test_node;

  db_sql_editor_tester.load_schema_list();
  db_sql_editor_tester.load_schema_data("wb_sql_editor_form_test");

  std::string error;
  std::string schema_name;
  std::string table_name;

  /* Failure case: using functions as columns */
  ensure("CHK001 Unexpected editable select success", !db_sql_editor_tester.is_editable_select("select count(*) from sakila.customer", schema_name, table_name, error));
  ensure_equals("CHK002 Unexpected error on editable select", error, "The statement is not editable.");

  /* Success case : using a non loaded schema, the required table will be loaded right away */
  ensure("CHK003 Unexpected editable select success", db_sql_editor_tester.is_editable_select("select * from sakila.customer", schema_name, table_name, error));
  ensure_equals("CHK004 Unexpected error on editable select", error, "");

  /* Success case : loading all columns from a table having primary key */
  ensure("CHK005 Unexpected editable select failure", db_sql_editor_tester.is_editable_select("select * from wb_sql_editor_form_test.film_text", schema_name, table_name, error));
  ensure_equals("CHK006 Unexpected error on editable select", error, "");

  /* Success case : loading columns include primary key */
  ensure("CHK007 Unexpected editable select failure", db_sql_editor_tester.is_editable_select("select film_id, title, description from wb_sql_editor_form_test.film_text", schema_name, table_name, error));
  ensure_equals("CHK008 Unexpected error on editable select", error, "");

  /* Failure case : loading columns not include primary key */
  ensure("CHK009 Unexpected editable select sucess", !db_sql_editor_tester.is_editable_select("select title, description from wb_sql_editor_form_test.film_text", schema_name, table_name, error));
  ensure_equals("CHK010 Unexpected error on editable select", error, "The select statement is missing primary key or unique non nullable columns on table film_text.");


  /* Success case : loading all columns from a table having complex primary key */
  ensure("CHK011 Unexpected editable select failure", db_sql_editor_tester.is_editable_select("select * from wb_sql_editor_form_test.complex_pk_table", schema_name, table_name, error));
  ensure_equals("CHK012 Unexpected error on editable select", error, "");

  /* Success case : loading columns include primary key but not all */
  ensure("CHK013 Unexpected editable select success", !db_sql_editor_tester.is_editable_select("select dummy_first_id, title, description from wb_sql_editor_form_test.complex_pk_table", schema_name, table_name, error));
  ensure_equals("CHK014 Unexpected error on editable select", error, "The select statement is missing primary key or unique non nullable columns on table complex_pk_table.");

  /* Success case : loading columns include all the primary key columns */
  ensure("CHK015 Unexpected editable select failure", db_sql_editor_tester.is_editable_select("select dummy_first_id, dummy_second_id, title, description from wb_sql_editor_form_test.complex_pk_table", schema_name, table_name, error));
  ensure_equals("CHK016 Unexpected error on editable select", error, "");


  /* failure case : loading all columns from a table not having primary key */
  ensure("CHK017 Unexpected editable select sucess", !db_sql_editor_tester.is_editable_select("select * from wb_sql_editor_form_test.no_pk_table", schema_name, table_name, error));
  ensure_equals("CHK018 Unexpected error on editable select", error, "Table no_pk_table has no primary keys or unique non nullable columns defined. Only tables with primary keys or unique non nullable columns can be edited.");


  /* Success case : loading all columns from a table having primary key and unique non nullable column */
  ensure("CHK020 Unexpected editable select failure", db_sql_editor_tester.is_editable_select("select * from wb_sql_editor_form_test.pk_table_unique_not_null", schema_name, table_name, error));
  ensure_equals("CHK021 Unexpected error on editable select", error, "");

  /* Success case : loading columns include primary key */
  ensure("CHK022 Unexpected editable select failure", db_sql_editor_tester.is_editable_select("select dummy_pk, title, description from wb_sql_editor_form_test.pk_table_unique_not_null", schema_name, table_name, error));
  ensure_equals("CHK023 Unexpected error on editable select", error, "");

  /* Success case : loading columns include unique non nullable column but not PK */
  ensure("CHK024 Unexpected editable select failure", db_sql_editor_tester.is_editable_select("select dummy_id, title, description from wb_sql_editor_form_test.pk_table_unique_not_null", schema_name, table_name, error));
  ensure_equals("CHK025 Unexpected error on editable select", error, "");

  /* Failure case : loading columns not include primary key nor unique non nullable column */
  ensure("CHK026 Unexpected editable select sucess", !db_sql_editor_tester.is_editable_select("select title, description from wb_sql_editor_form_test.pk_table_unique_not_null", schema_name, table_name, error));
  ensure_equals("CHK027 Unexpected error on editable select", error, "The select statement is missing primary key or unique non nullable columns on table pk_table_unique_not_null.");
  
  /* Success case : loading all columns from a table NOT having primary key BUT unique non nullable column */
  ensure("CHK030 Unexpected editable select failure", db_sql_editor_tester.is_editable_select("select * from wb_sql_editor_form_test.no_pk_table_unique_not_null", schema_name, table_name, error));
  ensure_equals("CHK031 Unexpected error on editable select", error, "");

  /* Success case : loading columns include unique non nullable column */
  ensure("CHK032 Unexpected editable select failure", db_sql_editor_tester.is_editable_select("select dummy_id, title, description from wb_sql_editor_form_test.no_pk_table_unique_not_null", schema_name, table_name, error));
  ensure_equals("CHK033 Unexpected error on editable select", error, "");

  /* Failure case : loading columns not unique non nullable column */
  ensure("CHK034 Unexpected editable select sucess", !db_sql_editor_tester.is_editable_select("select title, description from wb_sql_editor_form_test.no_pk_table_unique_not_null", schema_name, table_name, error));
  ensure_equals("CHK035 Unexpected error on editable select", error, "The select statement is missing primary key or unique non nullable columns on table no_pk_table_unique_not_null.");
}
END_TESTS