Beispiel #1
0
        protected InputFragment VisitInputExpression(DbExpression e, string name, TypeUsage type)
        {
            SqlFragment f = e.Accept(this);

            Debug.Assert(f is InputFragment);

            InputFragment inputFragment = f as InputFragment;

            inputFragment.Name = name;
            TryFusingSelect(inputFragment);

            if (inputFragment is TableFragment && type != null)
            {
                (inputFragment as TableFragment).Type = type;
            }

            SelectStatement select = inputFragment as SelectStatement;

            if ((select != null) && (select.From is TableFragment))
            {
                (select.From as TableFragment).Type = type;
            }

            if (name != null)
            {
                scope.Add(name, inputFragment);
            }

            return(inputFragment);
        }
        internal void AddColumn(ColumnFragment column, Scope scope)
        {
            InputFragment input = scope.FindInputFromProperties(column.PropertyFragment);

            column.TableName = input.Name;

            // then we rename the column if necessary
            if (columnHash.ContainsKey(column.ColumnName.ToUpper()))
            {
                column.ColumnAlias = MakeColumnNameUnique(column.ColumnName);
                columnHash.Add(column.ColumnAlias, column);
            }
            else
            {
                if (!string.IsNullOrEmpty(column.ColumnAlias))
                {
                    columnHash.Add(column.ColumnAlias.ToUpper(), column);
                }
                else
                {
                    columnHash.Add(column.ColumnName.ToUpper(), column);
                }
            }
            Columns.Add(column);
        }
Beispiel #3
0
        public InputFragment FindInputFromProperties(PropertyFragment fragment)
        {
            Debug.Assert(fragment != null);
            PropertyFragment propertyFragment = fragment as PropertyFragment;

            Debug.Assert(propertyFragment != null);

            if (propertyFragment.Properties.Count >= 2)
            {
                for (int x = propertyFragment.Properties.Count - 2; x >= 0; x--)
                {
                    string reference = propertyFragment.Properties[x];
                    if (reference == null)
                    {
                        continue;
                    }
                    InputFragment input = GetFragment(reference);
                    if (input == null)
                    {
                        continue;
                    }
                    if (input.Scoped)
                    {
                        return(input);
                    }
                    if (input is SelectStatement)
                    {
                        return((input as SelectStatement).From);
                    }
                    continue;
                }
            }
            Debug.Fail("Should have found an input");
            return(null);
        }
Beispiel #4
0
        public void Remove(string Name, InputFragment fragment)
        {
            if (fragment == null)
            {
                return;
            }
            if (Name != null)
            {
                scopeTable.Remove(Name);
            }

            if (fragment is SelectStatement)
            {
                Remove((fragment as SelectStatement).From);
            }
            else if (fragment is JoinFragment)
            {
                JoinFragment j = fragment as JoinFragment;
                Remove(j.Left);
                Remove(j.Right);
            }
            else if (fragment is UnionFragment)
            {
                UnionFragment u = fragment as UnionFragment;
                Remove(u.Left);
                Remove(u.Right);
            }
        }
Beispiel #5
0
 public void Remove(InputFragment fragment)
 {
     if (fragment == null)
     {
         return;
     }
     Remove(fragment.Name, fragment);
 }
Beispiel #6
0
        /// <summary>
        /// If current fragment is select and its from clause is another select, try fuse the inner select with the outer select.
        /// (Thus removing a nested query, which may have bad performance in Mysql).
        /// </summary>
        /// <param name="f">The fragment to probe and posibly optimize</param>
        /// <returns>The fragment fused, or the original one.</returns>
        protected internal InputFragment TryFusingSelect(InputFragment f)
        {
            SelectStatement result = f as SelectStatement;

            if (!CanFuseSelect(f as SelectStatement))
            {
                return(f);
            }
            result = FuseSelectWithInnerSelect(result, result.From as SelectStatement);
            return(result);
        }
 private InputFragment WrapJoinInputIfNecessary(InputFragment fragment, bool isRightPart)
 {
     if (fragment is SelectStatement || fragment is UnionFragment)
     {
         fragment.Wrap(scope);
         fragment.Scoped = true;
     }
     else if (fragment is JoinFragment && isRightPart)
     {
         SelectStatement select = new SelectStatement(this);
         select.From = fragment;
         select.Name = fragment.Name;
         select.Wrap(scope);
         return(select);
     }
     return(fragment);
 }
        private SelectStatement VisitInputExpressionEnsureSelect(DbExpression e, string name, TypeUsage type)
        {
            InputFragment fragment = VisitInputExpression(e, name, type);

            if (fragment is SelectStatement)
            {
                return(fragment as SelectStatement);
            }

            SelectStatement s = new SelectStatement(this);

            // if the fragment is a union then it needs to be wrapped
            if (fragment is UnionFragment)
            {
                (fragment as UnionFragment).Wrap(scope);
            }

            s.From = fragment;
            return(s);
        }
        void AddDefaultColumns(Scope scope)
        {
            if (columnHash == null)
            {
                columnHash = new Dictionary <string, ColumnFragment>();
            }

            List <ColumnFragment> columns = GetDefaultColumnsForFragment(From);
            bool Exists = false;

            if (From is TableFragment && scope.GetFragment((From as TableFragment).Table) == null)
            {
                scope.Add((From as TableFragment).Table, From);
                Exists = true;
            }

            foreach (ColumnFragment column in columns)
            {
                // first we need to set the input for this column
                InputFragment input = scope.FindInputFromProperties(column.PropertyFragment);
                column.TableName = input.Name;

                // then we rename the column if necessary
                if (columnHash.ContainsKey(column.ColumnName.ToUpper()))
                {
                    column.ColumnAlias = MakeColumnNameUnique(column.ColumnName);
                    columnHash.Add(column.ColumnAlias, column);
                }
                else
                {
                    columnHash.Add(column.ColumnName.ToUpper(), column);
                }
                Columns.Add(column);
            }
            if (Exists)
            {
                scope.Remove((From as TableFragment).Table, From);
            }
        }
        List <ColumnFragment> GetDefaultColumnsForFragment(InputFragment input)
        {
            List <ColumnFragment> columns = new List <ColumnFragment>();

            if (input is TableFragment)
            {
                return(GetDefaultColumnsForTable(input as TableFragment));
            }
            else if (input is JoinFragment || input is UnionFragment)
            {
                Debug.Assert(input.Left != null);
                if (input is UnionFragment)
                {
                    generator.Ops.Push(OpType.Union);
                }
                columns = GetDefaultColumnsForFragment(input.Left);
                if (input is JoinFragment && input.Right != null)
                {
                    List <ColumnFragment> right = GetDefaultColumnsForFragment(input.Right);
                    columns.AddRange(right);
                }
                if (input is UnionFragment)
                {
                    generator.Ops.Pop();
                }
            }
            else if (input is SelectStatement)
            {
                SelectStatement select = input as SelectStatement;
                foreach (ColumnFragment cf in select.Columns)
                {
                    ColumnFragment newColumn = new ColumnFragment(cf.TableName,
                                                                  string.IsNullOrEmpty(cf.ColumnAlias) ? cf.ActualColumnName : cf.ColumnAlias
                                                                  );
                    if (generator.GetTopOp() == OpType.Join)
                    {
                        newColumn.ColumnAlias = cf.ColumnAlias;
                        newColumn.PushInput(cf.ColumnName);
                        if (cf.TableName != null)
                        {
                            newColumn.PushInput(cf.TableName);
                        }
                    }
                    else
                    {
                        newColumn.PushInput(cf.ActualColumnName);
                        if (cf.TableName != null && cf.ColumnAlias == null)
                        {
                            newColumn.PushInput(cf.TableName);
                        }
                    }
                    if (select.Name != null)
                    {
                        newColumn.PushInput(select.Name); // add the scope
                    }
                    columns.Add(newColumn);
                }
                return(columns);
            }
            else
            {
                throw new NotImplementedException();
            }
            if (!String.IsNullOrEmpty(input.Name) && input.Name != From.Name)
            {
                foreach (ColumnFragment c in columns)
                {
                    c.PushInput(input.Name);
                }
            }
            return(columns);
        }
Beispiel #11
0
        public override SqlFragment Visit(DbPropertyExpression expression)
        {
            propertyLevel++;
            PropertyFragment fragment = expression.Instance.Accept(this) as PropertyFragment;

            fragment.Properties.Add(expression.Property.Name);
            propertyLevel--;

            // if we are not at the top level property then just return
            if (propertyLevel > 0)
            {
                return(fragment);
            }

            ColumnFragment column = new ColumnFragment(null, fragment.LastProperty);

            column.PropertyFragment = fragment;
            InputFragment input = scope.FindInputFromProperties(fragment);

            if (input != null)
            {
                column.TableName = input.Name;
            }

            // now we need to check if our column name was possibly renamed
            if (input is TableFragment)
            {
                if (!string.IsNullOrEmpty(input.Name))
                {
                    SelectStatement sf = scope.GetFragment(input.Name) as SelectStatement;
                    if (sf != null)
                    {
                        // Special case: undo alias in case of query fusing
                        for (int i = 0; i < sf.Columns.Count; i++)
                        {
                            ColumnFragment cf = sf.Columns[i];
                            if (column.ColumnName == cf.ColumnAlias)
                            {
                                column.ColumnName  = cf.ColumnName;
                                column.ColumnAlias = cf.ColumnAlias;
                                column.TableName   = input.Name;
                                return(column);
                            }
                        }
                    }
                }
                return(column);
            }

            SelectStatement select = input as SelectStatement;
            UnionFragment   union  = input as UnionFragment;

            if (select != null)
            {
                select.HasDifferentNameForColumn(column);
            }
            else if (union != null)
            {
                union.HasDifferentNameForColumn(column);
            }

            // input is a table, selectstatement, or unionstatement
            return(column);
        }
Beispiel #12
0
 public void Add(string name, InputFragment fragment)
 {
     scopeTable.Add(name, fragment);
 }
        /// <summary>
        /// If input sqlFragment is a group by structure, is flattened to remove some nested correlation queries.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private SqlFragment TryFlatteningGroupBy(SqlFragment input)
        {
            SelectStatement select = null;
            SelectStatement tmpFrag = null, tmpFrag2 = null, tmpFrag3 = null;
            InputFragment   table = null;
            string          objName = null, colName = null, queryName = null;

            // First part assert is a kind-of structure we are looking for
            tmpFrag = input as SelectStatement;
            if (tmpFrag == null)
            {
                goto NoChanges;
            }
            tmpFrag = (tmpFrag).From as SelectStatement;
            if (tmpFrag == null)
            {
                goto NoChanges;
            }
            queryName = tmpFrag.Name;
            if (tmpFrag.Columns.Count < 2)
            {
                goto NoChanges;
            }
            if (!(tmpFrag.Columns[0] is ColumnFragment))
            {
                goto NoChanges;
            }
            colName  = objName = (tmpFrag.Columns[0] as ColumnFragment).ActualColumnName;
            tmpFrag2 = tmpFrag.From as SelectStatement;
            if (tmpFrag2 == null)
            {
                goto NoChanges;
            }
            if (tmpFrag2.Columns.Count < 1 || !(tmpFrag2.Columns[0] is ColumnFragment))
            {
                goto NoChanges;
            }
            if (string.CompareOrdinal(objName, tmpFrag2.Columns[0].ActualColumnName) != 0)
            {
                goto NoChanges;
            }
            if (tmpFrag.Columns[1].Literal == null)
            {
                goto NoChanges;
            }
            tmpFrag2 = tmpFrag.Columns[1].Literal as SelectStatement;
            if (tmpFrag2 == null)
            {
                goto NoChanges;
            }
            if ((tmpFrag2.Columns.Count != 1) || !(tmpFrag2.Columns[0].Literal != null))
            {
                goto NoChanges;
            }
            tmpFrag3 = tmpFrag2.From as SelectStatement;
            if (tmpFrag3 == null)
            {
                goto NoChanges;
            }
            table = tmpFrag3.From as InputFragment;
            if (table == null)
            {
                goto NoChanges;
            }
            FunctionFragment func = tmpFrag2.Columns[0].Literal as FunctionFragment;

            if (tmpFrag3.Columns.Count != 1 || !(tmpFrag3.Columns[0] is ColumnFragment))
            {
                goto NoChanges;
            }
            if (func == null)
            {
                goto NoChanges;
            }
            // Yes it is the kind-of type we like, then optimize it
            select     = new SelectStatement(this);
            table.Name = null;
            string        tableName = null;
            TableFragment t         = tmpFrag3.From as TableFragment;

            if (t == null)
            {
                tableName = tmpFrag3.Columns[0].TableName;
            }
            else
            {
                tableName = t.Table;
            }
            select.From = table;
            select.Columns.Add(new ColumnFragment(tableName, colName));
            select.Columns.Add(new ColumnFragment(tableName, "C0")
            {
                ColumnAlias = "C1",
                Literal     = new FunctionFragment()
                {
                    Argument = new ColumnFragment(tableName, tmpFrag3.Columns[0].ActualColumnName),
                    Distinct = tmpFrag3.IsDistinct,
                    Name     = func.Name
                }
            });
            select.Wrap(null);
            select.Name = queryName;
            select.AddGroupBy(select.Columns[0]);
            (input as SelectStatement).From = select;
NoChanges:
            return(input);
        }
        public override SqlFragment Visit(DbApplyExpression expression)
        {
            DbExpressionBinding inputBinding = expression.Input;
            InputFragment       input        = VisitInputExpression(inputBinding.Expression, inputBinding.VariableName, inputBinding.VariableType);
            DbExpressionBinding applyBinding = expression.Apply;
            InputFragment       apply        = VisitInputExpression(applyBinding.Expression, applyBinding.VariableName, applyBinding.VariableType);
            SelectStatement     select       = new SelectStatement(this);
            bool isInputSelect = false;

            if (!(input is TableFragment))
            {
                input.Wrap(scope);
                isInputSelect = true;
            }
            apply.Wrap(scope);
            select.From = input;
            select.Wrap(scope);
            if (apply is SelectStatement)
            {
                SelectStatement applySel = apply as SelectStatement;
                foreach (ColumnFragment f in applySel.Columns)
                {
                    SelectStatement newColSelect = new SelectStatement(this);
                    newColSelect.From  = applySel.From;
                    newColSelect.Where = applySel.Where;
                    if (isInputSelect)
                    {
                        VisitAndReplaceTableName(newColSelect.Where, (input as SelectStatement).From.Name, input.Name, null);
                    }
                    newColSelect.Limit      = applySel.Limit;
                    newColSelect.OrderBy    = applySel.OrderBy;
                    newColSelect.Skip       = applySel.Skip;
                    newColSelect.GroupBy    = applySel.GroupBy;
                    newColSelect.IsDistinct = applySel.IsDistinct;
                    newColSelect.Columns.Add(f);

                    newColSelect.Wrap(scope);
                    scope.Add(applySel.From.Name, applySel.From);

                    ColumnFragment newCol = new ColumnFragment(apply.Name, f.ColumnName);
                    newCol.Literal = newColSelect;
                    newCol.PushInput(newCol.ColumnName);
                    newCol.PushInput(apply.Name);
                    select.AddColumn(newCol, scope);
                    if (string.IsNullOrEmpty(newCol.ColumnAlias))
                    {
                        newColSelect.Name  = newCol.ColumnName;
                        newCol.ColumnAlias = newCol.ColumnName;
                    }
                    scope.Remove(newColSelect);
                }
                scope.Remove(applySel.From);
                scope.Remove(apply);
            }
            else if (apply is UnionFragment)
            {
                UnionFragment uf = apply as UnionFragment;
                if (uf.Left == null || uf.Right == null)
                {
                    throw new Exception("Union fragment is not properly formed.");
                }

                var left  = uf.Left as SelectStatement;
                var right = uf.Right as SelectStatement;

                if (left == null || right == null)
                {
                    throw new NotImplementedException();
                }

                var whereleft  = left.Where as BinaryFragment;
                var whereright = right.Where as BinaryFragment;

                if (whereleft == null || whereright == null)
                {
                    throw new NotImplementedException();
                }

                LiteralFragment literalFragmentWhere = null;

                //checking where left
                if (whereleft.Left is ColumnFragment && whereleft.Right is ColumnFragment)
                {
                    // we replace the where part for a dummy one
                    if (whereright.Left is ColumnFragment && whereright.Right is ColumnFragment)
                    {
                        literalFragmentWhere = new LiteralFragment("1 = 1");
                    }
                }

                if (literalFragmentWhere == null)
                {
                    throw new NotImplementedException();
                }

                var leftouterjoin = new JoinFragment();
                leftouterjoin.JoinType = Metadata.GetOperator(DbExpressionKind.LeftOuterJoin);
                leftouterjoin.Name     = apply.Name;

                // validating that column fragment on the left matches the name
                // for the input fragment
                var leftColumnFragment = whereleft.Left as ColumnFragment;

                if (leftColumnFragment == null)
                {
                    throw new NotImplementedException();
                }

                if (!leftColumnFragment.TableName.Equals(input.Name))
                {
                    new NotImplementedException();
                }

                var conditionJoin = new BinaryFragment();
                conditionJoin.Left = whereleft.Left;

                //update to the new reference
                var newColumnFragment = whereright.Right as ColumnFragment;
                if (newColumnFragment != null)
                {
                    newColumnFragment.TableName = uf.Name;
                }
                conditionJoin.Right    = newColumnFragment;
                conditionJoin.Operator = whereleft.Operator;

                leftouterjoin.Condition = conditionJoin;

                (uf.Left as SelectStatement).Where  = literalFragmentWhere;
                (uf.Right as SelectStatement).Where = literalFragmentWhere;

                leftouterjoin.Left  = input;
                leftouterjoin.Right = uf;

                return(leftouterjoin);
            }
            return(select);
        }