private List<QueryColumn> BuildColumns(ExternalQueryInfo Query, DataTable dt, DataTable Internal, DataTable External)
        {
            List<QueryColumn> cols = new List<QueryColumn>();
            foreach (string column in Query.ColumnList.Split(','))
            {
                QueryColumn qc = new QueryColumn();
                string col = column.Trim();
                int periodIndex = col.IndexOf('.');
                if (periodIndex > 0 && periodIndex + 1 < col.Length)
                {
                    qc.Name = col.Substring(periodIndex + 1);
                    qc.Table = col.Substring(0, periodIndex) == Query.InternalAlias ? Internal : col.Substring(0, periodIndex) == Query.ExternalAlias ? External : null;
                }
                else
                {
                    qc.Name = col;
                    qc.Table = Internal.Columns.Contains(col) && !External.Columns.Contains(col) ? Internal : !Internal.Columns.Contains(col) && External.Columns.Contains(col) ? External : null;
                }

                if (qc.Table != null)
                {
                    cols.Add(qc);
                    dt.Columns.Add(col);
                }
            }

            return cols;
        }
 /// <summary>Sets the external data access object</summary>
 /// <param name="Query">ExternalQuery object holding all parameters</param>
 private void SetExternalDatabase(ExternalQueryInfo Query)
 {
     if (_browser.Tree.Cache.ContainsKey("ROOT"))
     {
         ServerItem si = _browser.Tree.Cache["ROOT"].FirstOrDefault(s => s.Name == Query.Server) as ServerItem;
         _externalDab =
             DataAccessFactory.GetDataAccess(si.DataAccess.ConnectionType, si.DataAccess.DataSource, si.DataAccess.SelectedDatabase, si.DataAccess.Authentication, si.DataAccess.Username, si.DataAccess.Password);
         string oldDb = _externalDab.SelectedDatabase;
         _externalDab.SetDatabase(Query.Database);
         if (_externalDab.SelectedDatabase.ToUpper() != Query.Database.ToUpper())
         {
             _externalDab.SetDatabase(oldDb);
             throw new Exception("Could not set the database context for the extraserver query.");
         }
     }
     else
     {
         throw new Exception("I'm sorry, I don't know what server that is.");
     }
 }
        private ResultSet SelectExternalData(ExternalQueryInfo Query)
        {
            ResultSet rs = null;

            try
            {
                //Make the queries and then argh!
                rs = new ResultSet();
                ResultSet internalRs = ProcessInternalQuery(_dab, Query.InternalQuery, false);
                SetExternalDatabase(Query);
                ResultSet externalRs = ProcessInternalQuery(_externalDab, Query.ExternalQuery, false);
                DataSet joinDs = new DataSet();
                joinDs.Tables.Add(internalRs.Data);
                joinDs.Tables.Add(externalRs.Data);
                joinDs.Tables[0].TableName = Query.InternalAlias;
                joinDs.Tables[1].TableName = Query.ExternalAlias;

                List<QueryColumn> cols = BuildColumns(Query, rs.Data, internalRs.Data, externalRs.Data);

                JoinClause jc = BuildJoinClause(Query, internalRs.Data, externalRs.Data);

                if (Query.JoinType.ToLower() == "inner" && jc != null)
                {
                    var rows =
                        from a in externalRs.Data.AsEnumerable()
                        join b in internalRs.Data.AsEnumerable()
                        on a[jc.ExternalCol].ToString().ToUpper() equals b[jc.InternalCol].ToString().ToUpper()
                        select new { a, b };
                    foreach (var row in rows)
                    {
                        List<object> Data = new List<object>();
                        foreach (QueryColumn col in cols)
                        {
                            if (col.Table.Equals(internalRs.Data))
                                Data.Add(row.b[col.Name]);
                            else
                                Data.Add(row.a[col.Name]);
                        }

                        rs.Data.LoadDataRow(Data.ToArray(), false);
                    }
                }
                else if (Query.JoinType.ToLower() == "left" && jc != null)
                {
                    var rows =
                        from b in internalRs.Data.AsEnumerable()
                        join a in externalRs.Data.AsEnumerable()
                            on b[jc.InternalCol].ToString().ToUpper() equals a[jc.ExternalCol].ToString().ToUpper() into abTemp
                        from ab in abTemp.DefaultIfEmpty()
                        select new { b, ab };
                    foreach (var row in rows)
                    {
                        List<object> Data = new List<object>();
                        foreach (QueryColumn col in cols)
                        {
                            if (col.Table.Equals(internalRs.Data))
                                Data.Add(row.b[col.Name]);
                            else
                                Data.Add(row.ab != null ? row.ab[col.Name] : null);
                        }

                        rs.Data.LoadDataRow(Data.ToArray(), false);
                    }
                }

                return rs;
            }
            catch
            {
                throw;
            }
            finally
            {
            }
        }
        /// <summary>Parses and executes an external query</summary>
        /// <param name="Query">Query to process</param>
        /// <returns>ResultSet object containing data and messages as a result of the given query</returns>
        private ResultSet ProcessExternalQuery(string Query)
        {
            CheckCancel();
            ResultSet rs = new ResultSet();
            ExternalQueryInfo myQuery = new ExternalQueryInfo();
            string pattern = string.Empty;
            if (Query.Trim().Substring(0, 6).ToLower() == "select")
            {
                pattern =
                    @"^\s*select(.*?)from\s*\(\s*(select.*?)\)\s*([a-z0-9]+)\s+(inner|outer|left|right|cross|full)\s+join\s+\(" +
                    BASE_PATTERN + @"\)\s*([a-z0-9]+)\s+on(.*?)$";
                Match mt = RunRegEx(pattern, Query);
                if (mt.Success)
                {
                    myQuery.Server = mt.Groups[5].Value;
                    myQuery.Database = mt.Groups[6].Value;
                    myQuery.ColumnList = mt.Groups[1].Value;
                    myQuery.InternalQuery = mt.Groups[2].Value;
                    myQuery.InternalAlias = mt.Groups[3].Value;
                    myQuery.JoinType = mt.Groups[4].Value;
                    myQuery.ExternalQuery = mt.Groups[7].Value;
                    myQuery.ExternalAlias = mt.Groups[8].Value;
                    myQuery.JoinClause = mt.Groups[9].Value;

                    rs = SelectExternalData(myQuery);
                }
            }
            else if (Query.Trim().Substring(0, 6).ToLower() == "insert")
            {
                pattern = @"^\s*insert\s+into\s+([a-z0-9\._\-#]+?)\s+(\(\s*([a-z0-9\,\s_\-]+?)\s*\)\s+)*?" + BASE_PATTERN + @"\s?;\s?$";
                Match mt = RunRegEx(pattern, Query);
                if (mt.Success)
                {
                    myQuery.Server = mt.Groups[4].Value;
                    myQuery.Database = mt.Groups[5].Value;
                    myQuery.ColumnList = mt.Groups[3].Value;
                    myQuery.InternalQuery = mt.Groups[1].Value;
                    myQuery.ExternalQuery = mt.Groups[6].Value;

                    rs = InsertExternalData(myQuery);
                }
            }
            else
            {
                throw new Exception("Invalid extraserver query syntax.");
            }

            return rs;
        }
        /// <summary>Inserts data from an external source to a local source</summary>
        /// <param name="Query">ExternalQuery object which contains all the necessary variables</param>
        private ResultSet InsertExternalData(ExternalQueryInfo Query)
        {
            ResultSet externalRs = null;

            try
            {
                string oldDb = string.Empty;

                //Get the server and database
                SetExternalDatabase(Query);

                //Grab the externalQuery from database on server
                externalRs = ProcessInternalQuery(_externalDab, Query.ExternalQuery, false);
                if (externalRs.Data.Rows.Count == 0)
                {
                    throw new Exception("No external data to insert!");
                }

                //Check for existence of table -- create if necessary
                if (!InsertTableExists(Query.InternalQuery))
                {
                    //TODO: Universal create table
                    throw new NotImplementedException();
                }

                if (_cancelPending)
                {
                    throw new Exception("Operation cancelled");
                }

                //Build the insert statement
                StringBuilder insertQuery = new StringBuilder("insert into " + Query.InternalQuery + " ");
                if (!string.IsNullOrEmpty(Query.ColumnList))
                {
                    insertQuery.Append("(" + Query.ColumnList + ") ");
                }
                insertQuery.Append("values (");

                List<string> columns = new List<string>();
                foreach (DataColumn col in externalRs.Data.Columns)
                {
                    insertQuery.Append("@" + col.ColumnName + ", ");
                    columns.Add(col.ColumnName);
                }

                insertQuery.Remove(insertQuery.Length - 2, 2);
                insertQuery.Append(")");

                //Start looping through them
                int rowsAffected = 0;
                foreach (DataRow row in externalRs.Data.Rows)
                {
                    CheckCancel();
                    _dab.ClearParameters();
                    foreach (string col in columns)
                    {
                        _dab.AddParameter("@" + col, row[col]);
                    }
                    rowsAffected += _dab.ExecuteNonQuery(insertQuery.ToString());
                }

                StringBuilder selectQuery = new StringBuilder("select ");
                if (string.IsNullOrEmpty(Query.ColumnList))
                {
                    selectQuery.Append("* ");
                }
                else
                {
                    selectQuery.Append(Query.ColumnList + " ");
                }
                selectQuery.Append("from ");
                selectQuery.Append(Query.InternalQuery);
                ResultSet rs = ProcessInternalQuery(_dab, selectQuery.ToString(), true);
                rs.Messages = rowsAffected.ToString() + " rows inserted\r\n\r\n" + rs.Messages;
                return rs;
            }
            finally
            {
                if(externalRs != null)
                    externalRs.Dispose();
                if (_externalDab != null)
                    _externalDab.Dispose();
            }
        }
 private JoinClause BuildJoinClause(ExternalQueryInfo Query, DataTable Internal, DataTable External)
 {
     JoinClause jc = new JoinClause();
     foreach (string colDef in Query.JoinClause.Split('='))
     {
         string col = colDef.Trim();
         int periodIndex = col.IndexOf('.');
         if (periodIndex > 0 && periodIndex + 1 < col.Length)
         {
             if (col.Substring(0, periodIndex) == Query.InternalAlias)
                 jc.InternalCol = col.Substring(periodIndex + 1);
             else if (col.Substring(0, periodIndex) == Query.ExternalAlias)
                 jc.ExternalCol = col.Substring(periodIndex + 1);
             else
                 jc = null;
         }
         else
         {
             if (Internal.Columns.Contains(col) && !External.Columns.Contains(col))
                 jc.InternalCol = col;
             else if (!Internal.Columns.Contains(col) && External.Columns.Contains(col))
                 jc.ExternalCol = col;
             else
                 jc = null;
         }
     }
     return jc;
 }