protected virtual Expression AnalyzeConstant(Expression expression, BuilderContext builderContext)
 {
     // we try to find a non-constant operand, and if we do, we won't change this expression
     foreach (var operand in expression.GetOperands())
     {
         if (!(operand is ConstantExpression))
             return expression;
     }
     // now, we just simply return a constant with new value
     try
     {
         var optimizedExpression = Expression.Constant(expression.Evaluate());
         // sometimes, optimizing an expression changes its type, and we just can't allow this.
         if (optimizedExpression.Type == expression.Type)
             return optimizedExpression;
     }
         // if we fail to evaluate the expression, then just return it
     catch (ArgumentException) { }
     return expression;
 }
Beispiel #2
0
 protected virtual SqlStatement BuildSelect(Expression select, QueryContext queryContext)
 {
     var sqlProvider = queryContext.DataContext.Vendor.SqlProvider;
     var selectClauses = new List<SqlStatement>();
     foreach (var selectExpression in select.GetOperands())
     {
         var expressionString = BuildExpression(selectExpression, queryContext);
         if (selectExpression is SelectExpression)
             selectClauses.Add(sqlProvider.GetParenthesis(expressionString));
         else
             selectClauses.Add(expressionString);
     }
     SelectExpression selectExp = select as SelectExpression;
     if (selectExp != null)
     {
         if (selectExp.Group.Count == 1 && selectExp.Group[0].GroupedExpression == selectExp.Group[0].KeyExpression)
         {
             // this is a select DISTINCT expression
             // TODO: better handle selected columns on DISTINCT: I suspect this will not work in some cases
             if (selectClauses.Count == 0)
             {
                 selectClauses.Add(sqlProvider.GetColumns());
             }
             return sqlProvider.GetSelectDistinctClause(selectClauses.ToArray());
         }
     }
     return sqlProvider.GetSelectClause(selectClauses.ToArray());
 }
Beispiel #3
0
        /// <summary>
        /// The simple part: converts an expression to SQL
        /// This is not used for FROM clause
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="queryContext"></param>
        /// <returns></returns>
        protected virtual SqlStatement BuildExpression(Expression expression, QueryContext queryContext)
        {
            var sqlProvider = queryContext.DataContext.Vendor.SqlProvider;
            var currentPrecedence = ExpressionQualifier.GetPrecedence(expression);
            // first convert operands
            var operands = expression.GetOperands();
            var literalOperands = new List<SqlStatement>();
            foreach (var operand in operands)
            {
                var operandPrecedence = ExpressionQualifier.GetPrecedence(operand);
                var literalOperand = BuildExpression(operand, queryContext);
                if (operandPrecedence > currentPrecedence)
                    literalOperand = sqlProvider.GetParenthesis(literalOperand);
                literalOperands.Add(literalOperand);
            }

            // then converts expression
            if (expression is SpecialExpression)
                return sqlProvider.GetLiteral(((SpecialExpression)expression).SpecialNodeType, literalOperands);
            if (expression is EntitySetExpression)
                expression = ((EntitySetExpression)expression).TableExpression;
            if (expression is TableExpression)
            {
                var tableExpression = (TableExpression)expression;
                if (tableExpression.Alias != null) // if we have an alias, use it
                {
                    return sqlProvider.GetColumn(sqlProvider.GetTableAlias(tableExpression.Alias),
                                                 sqlProvider.GetColumns());
                }
                return sqlProvider.GetColumns();
            }
            if (expression is ColumnExpression)
            {
                var columnExpression = (ColumnExpression)expression;
                if (columnExpression.Table.Alias != null)
                {
                    return sqlProvider.GetColumn(sqlProvider.GetTableAlias(columnExpression.Table.Alias),
                                                 columnExpression.Name);
                }
                return sqlProvider.GetColumn(columnExpression.Name);
            }
            if (expression is InputParameterExpression)
            {
                var inputParameterExpression = (InputParameterExpression)expression;
                if (expression.Type.IsArray)
                {
                    int i = 0;
                    List<SqlStatement> inputParameters = new List<SqlStatement>();
                    foreach (object p in (Array)inputParameterExpression.GetValue())
                    {
                        inputParameters.Add(new SqlStatement(new SqlParameterPart(sqlProvider.GetParameterName(inputParameterExpression.Alias + i.ToString()),
                                                          inputParameterExpression.Alias + i.ToString())));
                        ++i;
                    }
                    return new SqlStatement(sqlProvider.GetLiteral(inputParameters.ToArray()));
                }
                return
                    new SqlStatement(new SqlParameterPart(sqlProvider.GetParameterName(inputParameterExpression.Alias),
                                                          inputParameterExpression.Alias));
            }
            if (expression is SelectExpression)
                return Build((SelectExpression)expression, queryContext);
            if (expression is ConstantExpression)
                return sqlProvider.GetLiteral(((ConstantExpression)expression).Value);
            if (expression is GroupExpression)
                return BuildExpression(((GroupExpression)expression).GroupedExpression, queryContext);

            StartIndexOffsetExpression indexExpression = expression as StartIndexOffsetExpression;
            if (indexExpression!=null)
            {
                if (indexExpression.StartsAtOne)
                {
                    literalOperands.Add(BuildExpression(Expression.Constant(1), queryContext));
                    return sqlProvider.GetLiteral(ExpressionType.Add, literalOperands);
                }
                else
                    return literalOperands.First();
            }
            if (expression.NodeType == ExpressionType.Convert || expression.NodeType == ExpressionType.ConvertChecked)
            {
                var unaryExpression = (UnaryExpression)expression;
                var firstOperand = literalOperands.First();
                if (IsConversionRequired(unaryExpression))
                    return sqlProvider.GetLiteralConvert(firstOperand, unaryExpression.Type);
                return firstOperand;
            }
            return sqlProvider.GetLiteral(expression.NodeType, literalOperands);
        }
 /// <summary>
 /// Cuts tiers in CLR / SQL.
 /// The search for cut is top-down
 /// </summary>
 /// <param name="expression"></param>
 /// <param name="dataRecordParameter"></param>
 /// <param name="mappingContextParameter"></param>
 /// <param name="builderContext"></param>
 /// <returns></returns>
 protected virtual Expression CutOutOperands(Expression expression,
                                             ParameterExpression dataRecordParameter, ParameterExpression mappingContextParameter,
                                             BuilderContext builderContext)
 {
     // two options: we cut and return
     if (GetCutOutOperand(expression, builderContext))
     {
         // "cutting out" means we replace the current expression by a SQL result reader
         // before cutting out, we check that we're not cutting a table
         // in this case, we convert it into its declared columns
         if (expression is TableExpression)
         {
             return GetOutputTableReader((TableExpression)expression, dataRecordParameter,
                                         mappingContextParameter, builderContext);
         }
         // for EntitySets, we have a special EntitySet builder
         if (expression is EntitySetExpression)
         {
             return GetEntitySetBuilder((EntitySetExpression) expression, dataRecordParameter,
                                        mappingContextParameter, builderContext);
             // TODO record EntitySet information, so we can initalize it with owner
         }
         // then, the result is registered
         return GetOutputValueReader(expression, dataRecordParameter, mappingContextParameter, builderContext);
     }
     // or we dig down
     var operands = new List<Expression>();
     foreach (var operand in expression.GetOperands())
     {
         operands.Add(operand == null 
             ? null
             : CutOutOperands(operand, dataRecordParameter, mappingContextParameter, builderContext));
     }
     return expression.ChangeOperands(operands);
 }
 protected virtual Expression AnalyzeNull(Expression expression, BuilderContext builderContext)
 {
     // this first test only to speed up things a little
     if (expression.NodeType == ExpressionType.Equal || expression.NodeType == ExpressionType.NotEqual)
     {
         var operands = expression.GetOperands().ToList();
         var nullComparison = GetNullComparison(expression.NodeType, operands[0], operands[1]);
         if (nullComparison == null)
             nullComparison = GetNullComparison(expression.NodeType, operands[1], operands[0]);
         if (nullComparison != null)
             return nullComparison;
         return expression;
     }
     return expression;
 }
 protected virtual Expression AnalyzeConstant(Expression expression, BuilderContext builderContext)
 {
     // we try to find a non-constant operand, and if we do, we won't change this expression
     foreach (var operand in expression.GetOperands())
     {
         if (!(operand is ConstantExpression))
             return expression;
     }
     if (expression.NodeType == ExpressionType.Parameter)
         return expression;
     if (expression.NodeType == (ExpressionType)SpecialExpressionType.Like)
         return expression;
     // SETuse
     // If the value of the first SpecialExpressionType change this 999 should change too
     if ((short)expression.NodeType > 999)
         return expression;
     // now, we just simply return a constant with new value
     try
     {
         var optimizedExpression = Expression.Constant(expression.Evaluate());
         // sometimes, optimizing an expression changes its type, and we just can't allow this.
         if (optimizedExpression.Type == expression.Type)
             return optimizedExpression;
     }
         // if we fail to evaluate the expression, then just return it
     catch (ArgumentException) 
     {
         return expression;
     }
     return expression;
 }
 protected virtual string BuildSelect(Expression select, QueryContext queryContext)
 {
     var sqlProvider = queryContext.DataContext.Vendor.SqlProvider;
     var selectClauses = new List<string>();
     foreach (var selectExpression in select.GetOperands())
     {
         selectClauses.Add(BuildExpression(selectExpression, queryContext));
     }
     return sqlProvider.GetSelectClause(selectClauses.ToArray());
 }
        /// <summary>
        /// The simple part: converts an expression to SQL
        /// This is not used for FROM clause
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="queryContext"></param>
        /// <returns></returns>
        protected virtual string BuildExpression(Expression expression, QueryContext queryContext)
        {
            var sqlProvider = queryContext.DataContext.Vendor.SqlProvider;
            var currentPrecedence = ExpressionQualifier.GetPrecedence(expression);
            // first convert operands
            var operands = expression.GetOperands();
            var literalOperands = new List<string>();
            foreach (var operand in operands)
            {
                var operandPrecedence = ExpressionQualifier.GetPrecedence(operand);
                string literalOperand = BuildExpression(operand, queryContext);
                if (operandPrecedence > currentPrecedence)
                    literalOperand = sqlProvider.GetParenthesis(literalOperand);
                literalOperands.Add(literalOperand);
            }

            // then converts expression
            if (expression is SpecialExpression)
                return sqlProvider.GetLiteral(((SpecialExpression)expression).SpecialNodeType, literalOperands);
            if (expression is TableExpression)
            {
                var tableExpression = (TableExpression)expression;
                if (tableExpression.Alias != null) // if we have an alias, use it
                {
                    return sqlProvider.GetColumn(sqlProvider.GetTableAlias(tableExpression.Alias),
                                                 sqlProvider.GetColumns());
                }
                return sqlProvider.GetColumns();
            }
            if (expression is ColumnExpression)
            {
                var columnExpression = (ColumnExpression)expression;
                if (columnExpression.Table.Alias != null)
                {
                    return sqlProvider.GetColumn(sqlProvider.GetTableAlias(columnExpression.Table.Alias),
                                                 columnExpression.Name);
                }
                return sqlProvider.GetColumn(columnExpression.Name);
            }
            if (expression is InputParameterExpression)
                return sqlProvider.GetParameterName(((InputParameterExpression)expression).Alias);
            if (expression is SelectExpression)
                return Build((SelectExpression)expression, queryContext);
            if (expression is ConstantExpression)
                return sqlProvider.GetLiteral(((ConstantExpression)expression).Value);
            if (expression is GroupExpression)
                return BuildExpression(((GroupExpression)expression).GroupedExpression, queryContext);
            if (expression.NodeType == ExpressionType.Convert || expression.NodeType == ExpressionType.ConvertChecked)
                return sqlProvider.GetLiteralConvert(literalOperands.First(), (expression as UnaryExpression).Type);

            return sqlProvider.GetLiteral(expression.NodeType, literalOperands);
        }
 protected virtual Expression AnalyzeOperands(Expression expression, TranslationContext context)
 {
     var operands = expression.GetOperands().ToList();
       var newOperands = new List<Expression>();
       for (int operandIndex = 0; operandIndex < operands.Count; operandIndex++)
       {
       var op = operands[operandIndex];
       var newOp = Analyze(op, context);
       newOperands.Add(newOp);
       }
       return expression.ChangeOperands(newOperands, operands);
 }
        // TODO: (RI:) should be removed most likely
        protected Expression AnalyzeTimeSpanMemberAccess(Expression objectExpression, MemberInfo memberInfo)
        {
            //A timespan expression can be only generated in a c# query as a DateTime difference, as a function call return or as a paramter
            //this case is for the DateTime difference operation

            if (!(objectExpression is BinaryExpression))
                throw new NotSupportedException();

            var operands = objectExpression.GetOperands();

            bool absoluteSpam = memberInfo.Name.StartsWith("Total");
            string operationKey = absoluteSpam ? memberInfo.Name.Substring(5) : memberInfo.Name;

            Expression currentExpression;
            switch (operationKey)
            {
                case "Milliseconds":
                    currentExpression = Expression.Convert(CreateSqlFunction(SqlFunctionType.DateDiffInMilliseconds, operands.First(), operands.ElementAt(1)), typeof(double));
                    break;
                case "Seconds":
                    currentExpression = Expression.Divide(
                        Expression.Convert(CreateSqlFunction(SqlFunctionType.DateDiffInMilliseconds, operands.First(), operands.ElementAt(1)), typeof(double)),
                        Expression.Constant(1000.0));
                    break;
                case "Minutes":
                    currentExpression = Expression.Divide(
                            Expression.Convert(CreateSqlFunction(SqlFunctionType.DateDiffInMilliseconds, operands.First(), operands.ElementAt(1)), typeof(double)),
                            Expression.Constant(60000.0));
                    break;
                case "Hours":
                    currentExpression = Expression.Divide(
                            Expression.Convert(CreateSqlFunction(SqlFunctionType.DateDiffInMilliseconds, operands.First(), operands.ElementAt(1)), typeof(double)),
                            Expression.Constant(3600000.0));
                    break;
                case "Days":
                    currentExpression = Expression.Divide(
                            Expression.Convert(CreateSqlFunction(SqlFunctionType.DateDiffInMilliseconds, operands.First(), operands.ElementAt(1)), typeof(double)),
                            Expression.Constant(86400000.0));
                    break;
                default:
                    throw new NotSupportedException(string.Format("The operation {0} over the TimeSpan isn't currently supported", memberInfo.Name));
            }

            if (!absoluteSpam)
            {
                switch (memberInfo.Name)
                {
                    case "Milliseconds":
                        currentExpression = Expression.Convert(Expression.Modulo(Expression.Convert(currentExpression, typeof(long)), Expression.Constant(1000L)), typeof(int));
                        break;
                    case "Seconds":
                        currentExpression = Expression.Convert(Expression.Modulo(Expression.Convert(currentExpression, typeof(long)),
                                                              Expression.Constant(60L)), typeof(int));
                        break;
                    case "Minutes":
                        currentExpression = Expression.Convert(Expression.Modulo(Expression.Convert(currentExpression, typeof(long)),
                                                                Expression.Constant(60L)), typeof(int));
                        break;
                    case "Hours":
                        currentExpression = Expression.Convert(Expression.Modulo(Expression.Convert(
                                                                                        currentExpression, typeof(long)),
                                                                Expression.Constant(24L)), typeof(int));
                        break;
                    case "Days":
                        currentExpression = Expression.Convert(currentExpression, typeof(int));
                        break;
                }

            }
            return currentExpression;
        }
Beispiel #11
0
 protected virtual Expression CutOutSqlTier(Expression expression,
     ParameterExpression dataRecordParameter, ParameterExpression sessionParameter,
     Type expectedType,
     TranslationContext context)
 {
     expectedType = expectedType ?? expression.Type;
     // two options: we cut and return
     if (IsSqlTier(expression, context))
     {
         // "cutting out" means we replace the current expression by a SQL result reader
         // before cutting out, we check that we're not cutting a table in this case, we convert it into its declared columns
         if (expression is TableExpression)
           // RI: entity reader comes here
           return GetOutputTableReader((TableExpression)expression, dataRecordParameter,
                                         sessionParameter, context);
         // RI: single-value result goes here
         return GetOutputValueReader(expression, expectedType, dataRecordParameter, sessionParameter, context);
     }
     // RI: Anon types, custom types go here
     var newOperands = new List<Expression>();
     var operands = expression.GetOperands();
     var argTypes = expression.GetArgumentTypes();
     for(int i = 0; i < operands.Count; i++ ) {
       var op = operands[i];
       var newOp = op == null ? null : CutOutSqlTier(op, dataRecordParameter, sessionParameter, argTypes[i], context);
       newOperands.Add(newOp);
     }
     Expression newExpr;
     if (expression is MetaTableExpression)
       //Joins go here
       newExpr = ((MetaTableExpression)expression).ConvertToNew(newOperands);
     else
       newExpr =  expression.ChangeOperands(newOperands, operands);
     return newExpr;
 }
Beispiel #12
0
        protected virtual SqlStatement BuildExpression(Expression expression)
        {
            if (expression is ConstantExpression)
              return _sqlProvider.GetLiteral(((ConstantExpression)expression).Value);

            var currentPrecedence = ExpressionUtil.GetPrecedence(expression);
            // first convert operands
            var operands = expression.GetOperands();
            var literalOperands = new List<SqlStatement>();
            foreach (var operand in operands)
            {
                var operandPrecedence = ExpressionUtil.GetPrecedence(operand);
                var literalOperand = BuildExpression(operand);
                if (operandPrecedence > currentPrecedence)
                    literalOperand = _sqlProvider.GetParenthesis(literalOperand);
                literalOperands.Add(literalOperand);
            }

            if (expression is AliasedExpression) {
              var aliasExpr = (AliasedExpression) expression;
              return BuildExpression(aliasExpr.Expression); //Alias will be added later
            }
            // then converts expression
            if (expression is SqlFunctionExpression) {
              var specExpr = (SqlFunctionExpression)expression;
              //RI: Special case for multiple "*" operands
              if (specExpr.FunctionType == SqlFunctionType.Count && literalOperands.Count > 0) {
                literalOperands.Clear();
                literalOperands.Add("*");
              }
              return _sqlProvider.GetSqlFunction(specExpr.FunctionType, specExpr.ForceIgnoreCase, literalOperands);
            }
            if (expression is TableExpression)
            {
                var tableExpression = (TableExpression)expression;
                if (tableExpression.Alias != null) // if we have an alias, use it
                {
                    return _sqlProvider.GetColumn(_sqlProvider.GetTableAlias(tableExpression.Alias),
                                                 _sqlProvider.GetColumns());
                }
                return _sqlProvider.GetColumns();
            }

            //RI: We might have NewExpression here! Query: (from b in books select new {b.Title}).Count();
            // in this case the NewExpression is 'hidden' inside subquery and it is not visible to CutOutOperands
            // We just return list of arguments (columns) of New expression
            if (expression is NewExpression)
              return new SqlStatement(literalOperands);
            //RI: adding this
            if (expression is MetaTableExpression) {
              var metaTable = (MetaTableExpression)expression;
              return _sqlProvider.GetColumns();
            }

            if (expression is ColumnExpression)
            {
                var columnExpression = (ColumnExpression)expression;
                if(columnExpression.Table.Alias != null)
                {
                    return _sqlProvider.GetColumn(_sqlProvider.GetTableAlias(columnExpression.Table.Alias),
                                                 columnExpression.Name);
                }
                //RI: changed this to keep output type
                var sqlPart = new SqlLiteralPart(_sqlProvider.GetColumn(columnExpression.Name), expression.Type);
                return new SqlStatement(sqlPart);
                //return _sqlProvider.GetColumn(columnExpression.Name);
            }

            if (expression is ExternalValueExpression)  {
                var extValue = (ExternalValueExpression)expression;

                switch(extValue.SqlUse) {
                  case ExternalValueSqlUse.Literal:
                    var sql = _sqlProvider.GetLiteral(extValue.LiteralValue);
                    return sql;
                  case ExternalValueSqlUse.Parameter:
                    // In SQL templates the first 2 args are reserved for { and } symbols
                    return _sqlProvider.GetParameter(extValue);
                  default:
                    // we should never get here
                    Util.Throw("LINQ engine error: encountered ExternalValueExpression with invalid Usage type: {0}, Expression: {1}",
                      extValue.SqlUse, extValue.SourceExpression);
                    return null; //never happens
                }
            }
            if (expression is SelectExpression)
                return BuildSelectSql((SelectExpression)expression);
            if (expression is GroupExpression)
                return BuildExpression(((GroupExpression)expression).GroupedExpression);

            StartIndexOffsetExpression indexExpression = expression as StartIndexOffsetExpression;
            if (indexExpression!=null)
            {
                if (indexExpression.StartsAtOne)
                {
                    literalOperands.Add(BuildExpression(Expression.Constant(1)));
                    return _sqlProvider.GetLiteral(ExpressionType.Add, literalOperands);
                }
                else
                    return literalOperands.First();
            }
            if (expression.NodeType == ExpressionType.Convert || expression.NodeType == ExpressionType.ConvertChecked)
            {
                var unaryExpression = (UnaryExpression)expression;
                var firstOperand = literalOperands.First();
                if (IsConversionRequired(unaryExpression))
                    return _sqlProvider.GetLiteralConvert(firstOperand, unaryExpression.Type);
                return firstOperand;
            }
            if (expression is BinaryExpression || expression is UnaryExpression)
              return _sqlProvider.GetLiteral(expression.NodeType, literalOperands);

            if (expression is TableFilterExpression)
              return _sqlProvider.GetTableFilter((TableFilterExpression)expression);

            return _sqlProvider.GetLiteral(expression.NodeType, literalOperands);
        }
Beispiel #13
0
 protected virtual SqlStatement BuildSelectClause(Expression select)
 {
     var selectClauses = new List<SqlStatement>();
       var ops = select.GetOperands().ToList();
       foreach(var outputExpr in ops) {
     var exprString = BuildOutputExpression(outputExpr);
     selectClauses.Add(exprString);
       }
       SelectExpression selectExp = select as SelectExpression;
       if(selectExp != null) {
     if(selectExp.Group.Count == 1 && selectExp.Group[0].IsDistinct) {
       //RI: changed code
       var g = selectExp.Group[0];
       var outCols = new List<SqlStatement>();
       foreach(var col in g.Columns) {
         var sqlCol = col.Table.Alias == null ?
             _sqlProvider.GetColumn(col.Name) :
             _sqlProvider.GetColumn(_sqlProvider.GetTableAlias(col.Table.Alias), col.Name);
         if(!string.IsNullOrEmpty(col.Alias))
           sqlCol += " AS " + col.Alias;
         outCols.Add(sqlCol);
       }
       return _sqlProvider.GetSelectDistinctClause(outCols.ToArray());
       /*
       // this is a select DISTINCT expression
         // TODO: better handle selected columns on DISTINCT: I suspect this will not work in some cases
         if (selectClauses.Count == 0)
         {
             selectClauses.Add(_sqlProvider.GetColumns());
         }
         return _sqlProvider.GetSelectDistinctClause(selectClauses.ToArray());
        */
     }
       }
       return _sqlProvider.GetSelectClause(selectClauses.ToArray());
 }