internal FromClauseBase TryToSimplifyAdditionalFrom(AdditionalFromClause additionalFrom) { FromClauseBase from = additionalFrom; var sqe = from.FromExpression as SubQueryExpression; if (sqe != null) { var subquery = SubqueryGeneratorQueryModelVisitor.ParseSubquery(sqe.QueryModel, this, ContextName, Context.Select()); if (subquery.Joins.Count > 0 || subquery.ResultOperators.Any(it => it is CastResultOperator == false && it is DefaultIfEmptyResultOperator == false) || subquery.AdditionalJoins.Count > 0) { return(from); } return(TryToSimplifyMainFrom(sqe.QueryModel.MainFromClause)); } return(from); }
private static Func <string, T> ProjectExpression <T>(SubQueryExpression sqe, QueryParts parts) { var mqp = new MainQueryParts( parts.Locator, parts.ConverterFactory, parts.Simplifications, parts.ExpressionMatchers, parts.MemberMatchers, parts.ProjectionMatchers); var subquery = SubqueryGeneratorQueryModelVisitor.ParseSubquery(sqe.QueryModel, mqp, parts.ContextName, parts.Context.Select()); var newExpression = sqe.QueryModel.SelectClause.Selector as NewExpression; if (newExpression != null) { return(ProjectNew <T>(newExpression, parts, subquery)); } return(ProjectMapping <T>(sqe, parts, subquery)); }
private static bool CheckShortCircuitCount(SubQueryExpression expression, MainQueryParts queryParts, Action <Expression> visitExpression) { var subquery = SubqueryGeneratorQueryModelVisitor.ParseSubquery(expression.QueryModel, queryParts, true); if (subquery.ShouldQueryInMemory) { throw new NotImplementedException("Unsupported subquery. Please provide more info about query."); //return false; } var cnt = queryParts.CurrentSelectIndex; var mq = subquery.MainFrom.FromExpression as QuerySourceReferenceExpression; if (mq != null && subquery.Joins.Count == 0 && subquery.AdditionalJoins.Count == 0 && subquery.Conditions.Count == 0) { if (mq.ReferencedQuerySource.ItemType.IsGrouping()) { queryParts.AddSelectPart( expression.QueryModel.MainFromClause, "ARRAY_UPPER(\"{0}\".\"Values\", 1) AS \"_count_helper_{1}\"".With(mq.ReferencedQuerySource.ItemName, cnt), "_count_helper_" + cnt, expression.QueryModel.ResultTypeOverride, (_, dr) => dr.IsDBNull(cnt) ? 0 : Convert.ChangeType(dr.GetValue(cnt), expression.QueryModel.ResultTypeOverride)); return(true); } } var sql = subquery.BuildSqlString(false); queryParts.AddSelectPart( expression.QueryModel.MainFromClause, @"(SELECT COUNT(""{1}"") FROM ({2}) ""{1}"") AS ""{0}"" ".With( "_subquery_" + cnt, expression.QueryModel.MainFromClause.ItemName, sql), "_count_" + cnt, expression.QueryModel.ResultTypeOverride, (_, dr) => dr.IsDBNull(cnt) ? 0 : Convert.ChangeType(dr.GetValue(cnt), expression.QueryModel.ResultTypeOverride)); return(true); }
private void TryToSimplifyMainFrom() { var from = MainFrom; var sqe = from.FromExpression as SubQueryExpression; do { from = sqe.QueryModel.MainFromClause; var subquery = SubqueryGeneratorQueryModelVisitor.ParseSubquery(sqe.QueryModel, this); if (subquery.Conditions.Count > 0 || subquery.Joins.Count > 0 || subquery.ResultOperators.Any(it => it is CastResultOperator == false && it is DefaultIfEmptyResultOperator == false) || subquery.AdditionalJoins.Count > 0) { return; } sqe = from.FromExpression as SubQueryExpression; } while (sqe != null); from.ItemName = MainFrom.ItemName; MainFrom = from; }
private static bool CheckShortCircuitSum(SubQueryExpression expression, MainQueryParts queryParts, Action <Expression> visitExpression) { var subquery = SubqueryGeneratorQueryModelVisitor.ParseSubquery(expression.QueryModel, queryParts, true); if (subquery.ShouldQueryInMemory) { throw new NotImplementedException("Unsupported subquery. Please provide more info about query."); //return false; } var sql = subquery.BuildSqlString(false); var cnt = queryParts.CurrentSelectIndex; var selector = expression.QueryModel.SelectClause.Selector as MemberExpression; if (selector == null) { return(false); } var type = expression.QueryModel.ResultTypeOverride; if (type.IsNullable()) { type = type.GetGenericArguments()[0]; } queryParts.AddSelectPart( expression.QueryModel.MainFromClause, @"(SELECT SUM((""{1}"").""{3}"") FROM ({2}) ""{1}"") AS ""{0}""".With( "_subquery_" + cnt, expression.QueryModel.MainFromClause.ItemName, sql, selector.Member.Name), "_sum_" + cnt, expression.QueryModel.ResultTypeOverride, (_, __, dr) => dr.IsDBNull(cnt) ? 0 : Convert.ChangeType(dr.GetValue(cnt), type)); return(true); }
//TODO vjerojatno ponekad ne treba ignorirati expression public string GetQuerySourceFromExpression(string name, Type type, Expression fromExpression) { var me = fromExpression as MemberExpression; if (me != null) { var src = BuildMemberPath(me, true); if (src != null) { return(@"(SELECT sq as ""{1}"" FROM unnest({0}) sq) AS ""{1}""".With(src, name)); } } var sqe = fromExpression as SubQueryExpression; if (sqe != null) { if (sqe.QueryModel.CanUseMain()) { return(GetQuerySourceFromExpression(name, type, sqe.QueryModel.MainFromClause.FromExpression)); } //TODO hack za replaceanje generiranog id-a var subquery = SubqueryGeneratorQueryModelVisitor.ParseSubquery(sqe.QueryModel, this); var sql = "({0}) AS \"{1}\"".With(subquery.BuildSqlString(true), name); var grouping = sqe.QueryModel.ResultOperators.FirstOrDefault(it => it is GroupResultOperator) as GroupResultOperator; if (grouping == null && subquery.Selects.Count == 1) { return(sql.Replace("\"" + sqe.QueryModel.MainFromClause.ItemName + "\"", "\"" + name + "\"")); } return(sql); } var ce = fromExpression as ConstantExpression; if (ce != null) { var queryable = ce.Value as IQueryable; if (queryable != null) { return(GetQueryableExpression(name, queryable)); } if (ce.Type.IsArray || ce.Value is Array) { return(FormatStringArray(ce.Value, name, ce.Type)); } else if (ce.Value is IEnumerable) { return(FormatStringEnumerable(ce.Value, name, ce.Type)); } return("(SELECT {0} AS \"{1}\") AS \"{1}\"".With(ce.Value, name)); } var nae = fromExpression as NewArrayExpression; if (nae != null) { if (nae.Expressions.Count == 0) { //TODO support for zero throw new NotSupportedException("Expecting NewArray expressions. None found"); } var inner = string.Join(" UNION ALL ", nae.Expressions.Select(it => "SELECT {0} AS \"{1}\"".With(GetSqlExpression(it), name))); return("(" + inner + ") AS \"{0}\" ".With(name)); } if (fromExpression is QuerySourceReferenceExpression && fromExpression.Type.IsGrouping()) { var qse = fromExpression as QuerySourceReferenceExpression; return ("(SELECT (\"{0}\".\"Values\")[i].* FROM generate_series(1, array_upper(\"{0}\".\"Values\", 1)) i) AS \"{1}\"".With( qse.ReferencedQuerySource.ItemName, name)); } var pe = fromExpression as ParameterExpression; if (pe != null) { return("UNNEST({0}\"{1}\") AS \"{2}\"".With(ContextName, pe.Name, name)); } return(FromSqlSource(name, type)); }
//TODO vjerojatno ponekad ne treba ignorirati expression public string GetQuerySourceFromExpression(string name, Type type, Expression fromExpression) { var me = fromExpression as MemberExpression; if (me != null) { var qse = me.Expression as QuerySourceReferenceExpression; if (qse != null) { return(@"TABLE(""{0}"".""{1}"") ""{2}""".With( qse.ReferencedQuerySource.ItemName, me.Member.Name, name)); } } var sqe = fromExpression as SubQueryExpression; if (sqe != null) { if (sqe.QueryModel.CanUseMain()) { return(GetQuerySourceFromExpression(name, type, sqe.QueryModel.MainFromClause.FromExpression)); } //TODO hack za replaceanje generiranog id-a var subquery = SubqueryGeneratorQueryModelVisitor.ParseSubquery(sqe.QueryModel, this, ContextName, Context.Select()); var grouping = sqe.QueryModel.ResultOperators.FirstOrDefault(it => it is GroupResultOperator) as GroupResultOperator; if (grouping == null && subquery.Selects.Count == 1) { if (sqe.QueryModel.ResultOperators.Any(it => it is UnionResultOperator || it is ConcatResultOperator)) { var ind = subquery.Selects[0].Sql.IndexOf(" AS "); if (ind > 0) { var asName = subquery.Selects[0].Sql.Substring(ind + 4).Trim().Replace("\"", ""); if (asName != name) { subquery.Selects[0].Sql = subquery.Selects[0].Sql.Substring(0, ind + 4) + "\"" + name + "\""; } } else { subquery.Selects[0].Sql = subquery.Selects[0].Sql + " AS \"" + name + "\""; } return("(" + subquery.BuildSqlString(true) + ") \"" + name + "\""); } return("(" + subquery.BuildSqlString(true).Replace("\"" + sqe.QueryModel.MainFromClause.ItemName + "\"", "\"" + name + "\"") + ") \"" + name + "\""); } return("(" + subquery.BuildSqlString(true) + ") \"" + name + "\""); } var ce = fromExpression as ConstantExpression; if (ce != null) { var queryable = ce.Value as IQueryable; if (queryable != null) { return(GetQueryableExpression(name, queryable)); } var ien = ce.Value as IEnumerable; var array = ien != null?ien.Cast <object>().ToArray() : null; var firstElem = array != null?array.FirstOrDefault(it => it != null) : null; var elementType = firstElem != null?firstElem.GetType() : ce.Type.IsArray ? ce.Type.GetElementType() : ce.Type.IsGenericType ? ce.Type.GetGenericArguments()[0] : null; if (Context.CanUseParams && elementType != null) { var factory = ConverterFactory.GetVarrayParameterFactory(elementType); if (factory != null) { var p = Parameters.Add(factory(ce.Value as IEnumerable)); return(@"(SELECT sq$.OBJECT_VALUE as ""{1}"" FROM TABLE({0}) sq$)".With(p, name)); } } if (ce.Type.IsArray || ce.Value is Array) { return(FormatStringArray(ce.Value, name, ce.Type)); } else if (ce.Value is IEnumerable) { return(FormatStringEnumerable(ce.Value, name, ce.Type)); } //TODO: sql injection!? return("(SELECT {0} AS \"{1}\" FROM dual) \"{1}\"".With(ce.Value, name)); } var nae = fromExpression as NewArrayExpression; if (nae != null) { if (nae.Expressions.Count == 0) { //TODO support for zero throw new NotImplementedException("Expecting NewArrayExpression arguments. None found."); } var inner = string.Join(" UNION ALL ", nae.Expressions.Select(it => "SELECT {0} AS \"{1}\"".With(GetSqlExpression(it), name))); return("(" + inner + ") \"{0}\" ".With(name)); } if (fromExpression is QuerySourceReferenceExpression && fromExpression.Type.IsGrouping()) { var qse = fromExpression as QuerySourceReferenceExpression; //TODO: convert to Oracle version return ("(SELECT (\"{0}\".\"Values\")[i].* FROM generate_series(1, array_upper(\"{0}\".\"Values\", 1)) i) AS \"{1}\"".With( qse.ReferencedQuerySource.ItemName, name)); } var pe = fromExpression as ParameterExpression; if (pe != null) { return("TABLE({0}\"{1}\") \"{2}\"".With(ContextName, pe.Name, name)); } return(FromSqlSource(name, type)); }