#include "stdafx.h"

#include "mysql_sql_syntax_check.h"
#include "mysql_sql_parser_fe.h"


using namespace grt;


Mysql_sql_syntax_check::Null_state_keeper::~Null_state_keeper()
{
  _sql_parser->_check_sql_statement.disconnect();
}
#define NULL_STATE_KEEPER Null_state_keeper _nsk(this);


Mysql_sql_syntax_check::Mysql_sql_syntax_check(grt::GRT *grt)
:
Sql_parser_base(grt),
Mysql_sql_parser_base(grt),
Sql_syntax_check(grt)
{
  NULL_STATE_KEEPER
}


int Mysql_sql_syntax_check::check_sql(const std::string &sql)
{
  NULL_STATE_KEEPER
  _messages_enabled= true;
  _use_delimiter= false;

  Check_sql_statement do_check_slot;
  switch (_object_type)
  {
  case ot_trigger:
    do_check_slot= sigc::mem_fun(this, &Mysql_sql_syntax_check::do_check_trigger);
    break;
  case ot_view:
    do_check_slot= sigc::mem_fun(this, &Mysql_sql_syntax_check::do_check_view);
    break;
  case ot_routine:
    do_check_slot= sigc::mem_fun(this, &Mysql_sql_syntax_check::do_check_routine);
    break;
  default:
    do_check_slot= sigc::mem_fun(this, &Mysql_sql_syntax_check::do_check_sql);
    break;
  }

  int err_count= check_sql_statement(sql, do_check_slot);
  return (err_count ? 0 : 1);
}


int Mysql_sql_syntax_check::check_trigger(const std::string &sql)
{
  NULL_STATE_KEEPER
  _messages_enabled= false;
  _use_delimiter= true;
  int err_count= check_sql_statement(sql, sigc::mem_fun(this,
    &Mysql_sql_syntax_check::do_check_trigger));
  return (err_count ? 0 : 1);
}


int Mysql_sql_syntax_check::check_view(const std::string &sql)
{
  NULL_STATE_KEEPER
  _messages_enabled= false;
  _use_delimiter= true;
  int err_count= check_sql_statement(sql, sigc::mem_fun(this,
    &Mysql_sql_syntax_check::do_check_view));
  return (err_count ? 0 : 1);
}


int Mysql_sql_syntax_check::check_routine(const std::string &sql)
{
  NULL_STATE_KEEPER
  _messages_enabled= false;
  _use_delimiter= true;
  int err_count= check_sql_statement(sql, sigc::mem_fun(this,
    &Mysql_sql_syntax_check::do_check_routine));
  return (err_count ? 0 : 1);
}


int Mysql_sql_syntax_check::check_sql_statement(const std::string &sql, Check_sql_statement check_sql_statement)
{
  _check_sql_statement= check_sql_statement;
  _process_sql_statement= sigc::mem_fun(this, &Mysql_sql_syntax_check::process_sql_statement);

  Mysql_sql_parser_fe sql_parser_fe(_grtm->get_grt());
  sql_parser_fe.ignore_dml= false;

  // set delimiter for sql script if needed
  std::string sql_= (_use_delimiter ? "DELIMITER //\n" : "") + sql + (_use_delimiter ? "\n//" : "");

  return parse_sql_script(sql_parser_fe, sql_.c_str());
}


int Mysql_sql_syntax_check::process_sql_statement(const MyxSQLTreeItem *tree)
{
  if (!tree)
  {
    report_sql_error(_lineno, true, _err_tok_line_pos, _err_tok_len, _err_msg, 2);
    return 1;
  }

  if (tree)
    tree= tree->subitem(sql::_statement, sql::_create);

  if (!tree)
    return 1; //! select query shouldn't return error here

  if (pr_processed == _check_sql_statement(tree))
    return 0;
  else
    return 1;
}


Mysql_sql_parser_base::Parse_result Mysql_sql_syntax_check::do_check_sql(const MyxSQLTreeItem *tree)
{
  if (tree)
    return check_sql(tree);
  else
    return pr_irrelevant;
}


Mysql_sql_parser_base::Parse_result Mysql_sql_syntax_check::do_check_trigger(const MyxSQLTreeItem *tree)
{
  const MyxSQLTreeItem *trigger_tail= NULL;
  {
    static sql::symbol path1[]= { sql::_view_or_trigger_or_sp_or_event, sql::_definer_tail, sql::_ };
    static sql::symbol path2[]= { sql::_view_or_trigger_or_sp_or_event, sql::_no_definer_tail, sql::_ };
    static sql::symbol * paths[]= { path1, path2 };

    trigger_tail= tree->search_by_paths(paths, ARR_CAPACITY(paths));
    if (trigger_tail)
      trigger_tail= trigger_tail->subitem(sql::_trigger_tail);
  }

  if (trigger_tail && trigger_tail->subseq(sql::_TRIGGER_SYM))
    return check_trigger(tree, trigger_tail);
  else
    return pr_irrelevant;
}


Mysql_sql_parser_base::Parse_result Mysql_sql_syntax_check::do_check_view(const MyxSQLTreeItem *tree)
{
  const MyxSQLTreeItem *view_tail= NULL;
  {
    static sql::symbol path1[]= { sql::_view_or_trigger_or_sp_or_event, sql::_definer_tail, sql::_ };
    static sql::symbol path2[]= { sql::_view_or_trigger_or_sp_or_event, sql::_no_definer_tail, sql::_ };
    static sql::symbol path3[]= { sql::_view_or_trigger_or_sp_or_event, sql::_ };
    static sql::symbol * paths[]= { path1, path2, path3 };

    view_tail= tree->search_by_paths(paths, ARR_CAPACITY(paths));
    if (view_tail)
      view_tail= view_tail->subitem(sql::_view_tail);
  }

  if (view_tail)
    return check_view(tree, view_tail);
  else
    return pr_irrelevant;
}


Mysql_sql_parser_base::Parse_result Mysql_sql_syntax_check::do_check_routine(const MyxSQLTreeItem *tree)
{
  const MyxSQLTreeItem *routine_tail= NULL;
  {
    static sql::symbol path1[]= { sql::_view_or_trigger_or_sp_or_event, sql::_definer_tail, sql::_ };
    static sql::symbol path2[]= { sql::_view_or_trigger_or_sp_or_event, sql::_no_definer_tail, sql::_ };
    static sql::symbol * paths[]= { path1, path2 };

    routine_tail= tree->search_by_paths(paths, ARR_CAPACITY(paths));
    if (routine_tail)
    {
      static sql::symbol path1[]= { sql::_sp_tail, sql::_ };
      static sql::symbol path2[]= { sql::_sf_tail, sql::_ };
      static sql::symbol * paths[]= { path1, path2 };

      routine_tail= routine_tail->search_by_paths(paths, ARR_CAPACITY(paths));
    }
  }

  if (routine_tail)
    return check_routine(tree, routine_tail);
  else
    return pr_irrelevant;
}


Mysql_sql_parser_base::Parse_result Mysql_sql_syntax_check::check_sql(const MyxSQLTreeItem *tree)
{
  return pr_processed;
}


Mysql_sql_parser_base::Parse_result Mysql_sql_syntax_check::check_trigger(const MyxSQLTreeItem *tree, const MyxSQLTreeItem *trigger_tail)
{
  return pr_processed;
}


Mysql_sql_parser_base::Parse_result Mysql_sql_syntax_check::check_view(const MyxSQLTreeItem *tree, const MyxSQLTreeItem *view_tail)
{
  return pr_processed;
}


Mysql_sql_parser_base::Parse_result Mysql_sql_syntax_check::check_routine(const MyxSQLTreeItem *tree, const MyxSQLTreeItem *routine_tail)
{
  return pr_processed;
}
