using FastReport.Data;
using FastReport.Forms;
using FastReport.Utils;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Windows.Forms;
namespace FastReport.FastQueryBuilder
{
internal class Core
{
private IQueryDesigner queryDesigner;
private DataBase dataBase;
private DialogResult dialogResult;
private Query query = new Query();
// unstable features
private bool unstableFeatures;
private bool unstableFeaturesForce;
public Core(IQueryDesigner qd, DataBase db)
{
unstableFeatures = true;
dataBase = db;
queryDesigner = qd;
queryDesigner.OnOk += OnOk;
queryDesigner.OnCancel += OnCancel;
queryDesigner.OnGetTableList += OnGetTableList;
queryDesigner.OnAddTable += OnAddTable;
queryDesigner.OnGenerateSQL += OnGenerateSQL;
queryDesigner.OnRunSQL += OnRunSQL;
queryDesigner.Fields = query.SelectedFields;
queryDesigner.Groups = query.GroupedFields;
queryDesigner.Links = query.LinkList;
}
public bool UseJoin { get; set; } = true;
public DialogResult DesignQuery()
{
queryDesigner.DesignQuery();
return dialogResult;
}
private void OnOk(object sender, EventArgs e)
{
dialogResult = DialogResult.OK;
queryDesigner.Close();
}
private void OnCancel(object sender, EventArgs e)
{
dialogResult = DialogResult.Cancel;
queryDesigner.Close();
}
private void OnGetTableList(object sender, EventArgs e)
{
queryDesigner.DoFillTableList(dataBase.TableList);
}
private Table FindTable(List
list, string tableName)
{
foreach (Table table in list)
{
if (table.Name == tableName)
return table;
}
return null;
}
private void OnAddTable(object sender, AddTableEventArgs e)
{
Table tbl = (Table)e.table.Clone();
tbl.Alias = GetUniqueAlias(tbl, e.alias);
query.TableList.Add(tbl);
var tv = queryDesigner.DoAddTable(tbl, e.position);
tv.OnAddLink += OnAddLink;
tv.OnSelectField += OnSelectField;
tv.OnDeleteTable += OnDeleteTable;
e.tableView = tv;
}
private Field FindSelectedField(SqlParser.FieldStruct fs)
{
foreach (Field f in query.SelectedFields)
{
if ((f.Table.Alias == fs.Table || f.Table.Name == fs.Table) && FieldEqFieldStruct(f, fs))
{
return f;
}
}
return null;
}
private Field FindField(SqlParser.FieldStruct fs)
{
foreach (Table t in query.TableList)
{
if (t.Name == fs.Table || t.Alias == fs.Table)
{
foreach (Field f in t.FieldList)
{
if (FieldEqFieldStruct(f, fs))
return f;
}
}
}
return null;
}
private bool FieldEqFieldStruct(Field f, SqlParser.FieldStruct fs)
{
return f.Name == fs.Name ||
!String.IsNullOrEmpty(f.Alias) && f.Alias == fs.Name ||
!String.IsNullOrEmpty(fs.Alias) && f.Name == fs.Alias ||
!String.IsNullOrEmpty(f.Alias) && !String.IsNullOrEmpty(fs.Alias) && f.Alias == fs.Alias;
}
private bool hasDuplicate(string alias)
{
foreach (Table t in query.TableList)
{
if (t.Alias == alias)
return true;
}
return false;
}
private string GetUniqueAlias(Table tbl, string al)
{
if (string.IsNullOrEmpty(al))
{
al = tbl.Name[0].ToString().ToUpper();
if (al[0] < 'A' || al[0] > 'Z')
al = "A";
}
int n = 1;
while (hasDuplicate(al))
{
al = tbl.Name[0] + n.ToString();
n++;
}
return al;
}
private void OnDeleteTable(object sender, AddTableEventArgs e)
{
for (int i = query.SelectedFields.Count - 1; i >= 0; i--)
{
if (query.SelectedFields[i].Table == e.table)
query.SelectedFields.RemoveAt(i);
}
query.DeleteTable(e.table);
queryDesigner.Fields = query.SelectedFields;
}
private void OnAddLink(object sender, AddLinkEventArgs e)
{
Link lnk;
if (LinkHasFrom(query.LinkList, e.fieldTo.Table))
lnk = new Link(e.fieldTo, e.fieldFrom);
else
lnk = new Link(e.fieldFrom, e.fieldTo);
if (LinkHas(query.LinkList, lnk))
return;
if (!e.useDefaults)
{
lnk.Join = e.joinType;
lnk.Where = e.whereType;
}
else
{
lnk.Join = UseJoin ? QueryEnums.JoinTypes.InnerJoin : QueryEnums.JoinTypes.Where;
lnk.Where = QueryEnums.WhereTypes.Equal;
}
query.LinkList.Add(lnk);
}
private bool LinkHas(List list, Link lnk)
{
foreach (Link link in list)
{
if (link.From == lnk.From && link.To == lnk.To)
return true;
}
return false;
}
private bool LinkHasFrom(List list, Table from)
{
foreach (Link link in list)
{
if (link.From.Table == from)
return true;
}
return false;
}
private void OnSelectField(object sender, CheckFieldEventArgs e)
{
if (e.value)
{
query.SelectedFields.Add(e.field);
}
else
{
query.SelectedFields.Remove(e.field);
}
queryDesigner.Fields = query.SelectedFields;
}
private void OnGenerateSQL(object sender, EventArgs e)
{
var sqlGen = new SQLGenerator(query);
sqlGen.qch = dataBase.GetQuotationChars();
queryDesigner.SQLText = sqlGen.getSql();
#region Debug
//queryDesigner.SQLText += "\n\n\n\n/*Tables:\n";
//foreach (Table tbl in query.TableList)
//{
// queryDesigner.SQLText += tbl.Name + "\n";
//}
//queryDesigner.SQLText += "\nLinks:\n";
//foreach (Link lnk in query.LinkList)
//{
// queryDesigner.SQLText += lnk.From.Table + ":" + lnk.From.Name + " => " + lnk.To.Table + ":" + lnk.To.Name + "\n";
//}
//queryDesigner.SQLText += "\nFields:\n";
//foreach (Field fld in query.SelectedFields)
//{
// queryDesigner.SQLText += fld.Table.ToString() + '.' + fld.Name + "\n";
//}
//queryDesigner.SQLText += "*/";
#endregion
}
private void OnRunSQL(object sender, EventArgs e)
{
var sqlGen = new SQLGenerator(query);
sqlGen.qch = dataBase.GetQuotationChars();
string sql = string.IsNullOrEmpty(queryDesigner.SQLText) ? sqlGen.getSql() : queryDesigner.SQLText;
DataTable table = new DataTable();
DataConnectionBase dataConnection = dataBase.dataBase;
DbConnection conn = dataConnection.GetConnection();
try
{
dataConnection.OpenConnection(conn);
using (DbDataAdapter adapter = dataConnection.GetAdapter(sql, conn, new CommandParameterCollection(null)))
{
table.Clear();
adapter.Fill(table);
}
}
finally
{
dataConnection.DisposeConnection(conn);
}
queryDesigner.DataSource = table;
}
public string GetSql()
{
if (string.IsNullOrEmpty(queryDesigner.SQLText))
OnGenerateSQL(null, null);
return queryDesigner.SQLText;
}
public void SetSql(string sql)
{
if (unstableFeatures && !string.IsNullOrEmpty(sql))
{
var parser = new SqlParser(sql);
parser.qch = dataBase.GetQuotationChars();
var tableViews = new List();
try
{
parser.Parse();
List tables = dataBase.TableList;
// add tables
foreach (SqlParser.TableStruct t in parser.Tables)
{
if (!unstableFeatures)
break;
Table table = FindTable(tables, t.Name);
if (table != null)
{
var args = new AddTableEventArgs(table, System.Drawing.Point.Empty, t.Alias);
OnAddTable(queryDesigner, args);
tableViews.Add(args.tableView);
}
else
{
ShowError(new FormatException("Table " + t.Name + " is not found!"));
}
}
if (unstableFeatures)
{
// select fields
foreach (SqlParser.FieldStruct fs in parser.Fields)
{
if (!unstableFeatures)
break;
string tableName = fs.Table;
foreach (ITableView tv in tableViews)
{
if (!unstableFeatures)
break;
Table tbl = tv.Table;
if (tbl.Name == tableName || tbl.Alias == tableName)
{
if (!tv.SelectCheckBox(fs.Name, fs.Func, fs.Alias))
ShowError(new FormatException("Field " + fs.Name + " is not found!"));
break;
}
}
}
foreach (SqlParser.FieldStruct fs in parser.Where)
{
if (!unstableFeatures)
break;
Field f = FindSelectedField(fs);
if (f == null)
{
ShowError(new FormatException("Field " + fs.Name + " is not found!"));
}
else
{
f.Filter = fs.Filter;
}
}
foreach (SqlParser.FieldStruct fs in parser.Groups)
{
if (!unstableFeatures)
break;
Field f = FindSelectedField(fs);
if (f == null)
{
ShowError(new FormatException("Field " + fs.Name + " is not found!"));
}
else
{
f.Group = true;
query.GroupedFields.Add(f);
}
}
foreach (SqlParser.FieldStruct fs in parser.Orders)
{
if (!unstableFeatures)
break;
Field f = FindSelectedField(fs);
if (f == null)
{
ShowError(new FormatException("Field " + fs.Name + " is not found!"));
}
else
{
switch (fs.SortType)
{
case SortTypes.Asc:
f.Order = "Asc";
break;
case SortTypes.Desc:
f.Order = "Desc";
break;
}
}
}
}
if (unstableFeatures)
{
foreach (SqlParser.LinkStruct ls in parser.Links)
{
if (!unstableFeatures)
break;
Field fieldFrom = FindField(ls.One);
Field fieldTo = FindField(ls.Two);
if (fieldFrom == null)
{
ShowError(new FormatException("Field " + ls.One + " is not found!"));
}
if (fieldTo == null)
{
ShowError(new FormatException("Field " + ls.Two + " is not found!"));
}
if (fieldFrom != null && fieldTo != null)
OnAddLink(queryDesigner, new AddLinkEventArgs(fieldFrom, fieldTo, ls.JoinType, ls.WhereType));
}
}
if (unstableFeatures && !unstableFeaturesForce)
{
var sqlGen = new SQLGenerator(query);
sqlGen.qch = dataBase.GetQuotationChars();
string newSql = sqlGen.getSql();
var lexerOld = new SqlLexer(sql, sqlGen.qch);
var lexerNew = new SqlLexer(newSql, sqlGen.qch);
var tokensOld = lexerOld.Parse();
var tokensNew = lexerNew.Parse();
bool isSqlEquals = true;
if (tokensOld.Count != tokensNew.Count)
{
isSqlEquals = false;
}
else
{
for (int i = 0; i < tokensOld.Count; i++)
{
if (!tokensOld[i].Equals(tokensNew[i]))
{
isSqlEquals = false;
break;
}
}
}
if (!isSqlEquals)
ShowError(new Exception("Sql is not equals"));
}
if (!unstableFeatures)
{
query.LinkList.Clear();
query.SelectedFields.Clear();
query.GroupedFields.Clear();
query.TableList.Clear();
queryDesigner.Clear();
queryDesigner.Fields = query.SelectedFields;
}
}
catch (Exception e)
{
ShowError(e);
}
}
}
private void ShowError(Exception e)
{
#if DEBUG
ExceptionForm form = new ExceptionForm(e);
form.ShowDialog();
#endif
if (unstableFeatures && !unstableFeaturesForce)
{
switch (MessageBox.Show(Res.Get("Forms,QueryBuilder,QueryIsCorrupted"),
Res.Get("Forms,QueryBuilder,QueryIsCorruptedTitle"),
MessageBoxButtons.YesNo, MessageBoxIcon.Warning))
{
case DialogResult.Yes:
unstableFeaturesForce = true;
break;
case DialogResult.No:
unstableFeatures = false;
break;
}
}
}
}
}