Example #1
0
        // 集約関数の場合、Trueを返す
        internal bool IsAggregative()
        {
            if (this.Node == null || this.Node.IsTableWildcard)
            {
                return(false);
            }
            var exprValue = ((ResultExpr)this.Node).Value;
            var visitor   = new FindAggregateExprVisitor();

            exprValue.Accept(visitor);
            return(visitor.ContainsAggregativeExpr);
        }
Example #2
0
        private void ReplaceColumnNameInOrderBy(IQuery query)
        {
            // queryのSELECT句情報を取得する
            var mainQueryResults = this.GetResults((IQueryClause)query);

            foreach (var candidateReplaceColumn in _candidateReplaceColumns)
            {
                Column replaceColumn    = null;
                string newAliasName     = null;
                bool   aliasNameIsFound = false;

                foreach (var mainQueryResult in mainQueryResults)
                {
                    var aliasName = mainQueryResult.Item2;

                    // ORDER BY句でAS別名を参照するColumnはTableAliasNameを指定できない
                    if (string.IsNullOrEmpty(candidateReplaceColumn.Item2.TableAliasName) &&
                        aliasName == candidateReplaceColumn.Item2.Name)
                    {
                        // AS別名で参照しているOrderBy句は、そのまま置き換えない
                        replaceColumn    = null;
                        aliasNameIsFound = true;
                        break;
                    }
                    else if (mainQueryResult.Item1 != null)
                    {
                        var resultColumn = mainQueryResult.Item1;
                        if (this.IsEqual(resultColumn, candidateReplaceColumn.Item2))
                        {
                            // Column名で参照しているOrderBy句は、
                            // AS別名で参照するように置き換える
                            replaceColumn = candidateReplaceColumn.Item2;
                            newAliasName  = aliasName;
                        }
                    }
                } // foreach

                // ORDER BY句のColumnオブジェクトをAS別名に変換する
                if (replaceColumn != null)
                {
                    replaceColumn.ServerName     = null;
                    replaceColumn.DataBaseName   = null;
                    replaceColumn.SchemaName     = null;
                    replaceColumn.TableAliasName = null;
                    replaceColumn.Name           = newAliasName;
                }
                else if (!aliasNameIsFound)
                {
                    // CompoundQueryの場合SELECT句に無い列はORDER BY句で参照できないので、
                    // SELECT句に補完しない
                    var queryClause = (IQueryClause)query;
                    while (queryClause.Type == QueryType.Bracketed)
                    {
                        queryClause = ((BracketedQueryClause)queryClause).Operand;
                    }
                    if (queryClause.Type == QueryType.Compound)
                    {
                        //
                        this.RemoveOrderingTerm(query.OrderBy, candidateReplaceColumn.Item1);
                        continue;
                    }
                    var singleQueryClause = (SingleQueryClause)queryClause;

                    // DISTINCTの指定がある場合、SELECT句に補完しない
                    if (singleQueryClause.Quantifier == QuantifierType.Distinct)
                    {
                        this.RemoveOrderingTerm(query.OrderBy, candidateReplaceColumn.Item1);
                        continue;
                    }

                    if (singleQueryClause.HasGroupBy)
                    {
                        // DISTINCTの指定が無く、GROUP BY句にORDER BY句で指定するColumnがある場合
                        // そのColumnを参照するSELECT句を補完する
                        var foundInGroupBy = false;
                        foreach (var g in singleQueryClause.GroupBy)
                        {
                            if (g.GetType() == typeof(Column))
                            {
                                if (this.IsEqual((Column)g, candidateReplaceColumn.Item2))
                                {
                                    this.AppendResult(query, (Column)candidateReplaceColumn.Item2.Clone());
                                    foundInGroupBy = true;
                                    break;
                                }
                            }
                        } // foreach

                        // GROUP BY句にORDER BY句で指定するColumnがない場合、そのOrderingTerm句を削除する
                        if (!foundInGroupBy)
                        {
                            this.RemoveOrderingTerm(query.OrderBy, candidateReplaceColumn.Item1);
                        }
                    }
                    else
                    {
                        // GROUP BY句がなく集約関数のみの場合、SELECT句に補完しない
                        var aggregateFinder = new FindAggregateExprVisitor();
                        singleQueryClause.Results.Accept(aggregateFinder);
                        if (aggregateFinder.ContainsAggregativeExpr)
                        {
                            this.RemoveOrderingTerm(query.OrderBy, candidateReplaceColumn.Item1);
                            continue;
                        }

                        // SELECT句にORDER BY句が指定するAS別名またはColumnが無いが、
                        // 抽出元にある場合は、その抽出元を参照するSELECT句を補完する
                        foreach (var resultInfo in _stack.Peek())
                        {
                            if (resultInfo.IsDirectSource(candidateReplaceColumn.Item2, _ignoreCase))
                            {
                                this.AppendResult(query, (Column)candidateReplaceColumn.Item2.Clone());
                                break;
                            }
                        } // foreach
                    }
                }         // if
            }             // foreach
        }
        public sealed override void VisitAfter(SingleQueryClause query)
        {
            // ReadロックはReadするテーブル行をロックするのが目的なので、その行を抽出するための条件
            // (EXISTS, IN, ..)で用いられるサブクエリ内のテーブル行はロックしない
            if (this.IsNotInMainResultsSource())
            {
                return;
            }

            //
            // このQueryの列情報(ResultInfoList)を作成する
            //

            // 作成するこのQueryの列情報
            var resultInfoList = new ResultInfoList();
            // SELECT句サブクエリ
            var subQueries = new Stack <ResultInfoList>();
            // FROM句の抽出元テーブル列
            ResultInfoList sources;

            while (true)
            {
                ResultInfoList subQuery = _stack.Pop();
                if (subQuery.IsSubQueryInResults)
                {
                    subQueries.Push(subQuery);
                }
                else if (this.CurrentSubQueryIs(SubQueryType.Exists))
                {
                    // Existsサブクエリの場合はSELECT句情報を作成しない
                    return;
                }
                else if (this.CurrentSubQueryIs(SubQueryType.OrderBy))
                {
                    // OrderByサブクエリの場合はSELECT句情報を作成しない
                    return;
                }
                else
                {
                    sources = subQuery;
                    break;
                }
            }

            if (query.HasWildcard)
            {
                foreach (var source in sources)
                {
                    resultInfoList.Add(new ResultInfo("", source.ColumnAliasName, null, source));
                }
                _stack.Push(resultInfoList);
                return;
            }

            foreach (var resultColumn in query.Results)
            {
                if (resultColumn.IsTableWildcard)
                {
                    var tableWildcard = (TableWildcard)resultColumn;
                    foreach (var source in sources)
                    {
                        if (source.TableAliasName == tableWildcard.TableAliasName)
                        {
                            resultInfoList.Add(new ResultInfo("", source.ColumnAliasName, tableWildcard, source));
                        }
                    }
                }
                else
                {
                    var resultExpr = (ResultExpr)resultColumn;
                    if (resultExpr.Value.GetType() == typeof(Column))
                    {
                        // sourcesから参照元のResultInfoを見つける
                        var column          = (Column)resultExpr.Value;
                        var columnAliasName = string.IsNullOrEmpty(resultExpr.AliasName) ? column.Name : resultExpr.AliasName;
                        var foundInSources  = false;
                        foreach (var source in sources)
                        {
                            if (source.IsDirectSource(column, _ignoreCase))
                            {
                                resultInfoList.Add(new ResultInfo("", columnAliasName, resultExpr, source));
                                foundInSources = true;
                                break;
                            }
                        }
                        // 参照元のResultInfoが見つからない場合(抽出元テーブルの列名が不明な場合等)
                        // UNIONでResultInfoをマージするためSELECT句には必ずResultInfoを用意する
                        if (!foundInSources)
                        {
                            resultInfoList.Add(new ResultInfo("", columnAliasName, resultExpr));
                        }
                    }
                    else if (resultExpr.Value.GetType() == typeof(SubQueryExp))
                    {
                        var subQueryExp        = (SubQueryExp)resultExpr.Value;
                        var subQueryResultInfo = subQueries.Pop();
                        if (subQueryResultInfo.Count == 0)
                        {
                            resultInfoList.Add(new ResultInfo("", resultExpr.AliasName, resultExpr, null));
                        }
                        else
                        {
                            resultInfoList.Add(new ResultInfo("", resultExpr.AliasName, resultExpr, subQueryResultInfo[0]));
                        }
                    }
                    else
                    {
                        // UNIONでResultInfoをマージするためSELECT句には必ずResultInfoを用意する
                        resultInfoList.Add(new ResultInfo("", resultExpr.AliasName, resultColumn));
                    }
                } // if
            }     // for

            if (query.HasGroupBy)
            {
                // GROUP BY句がある場合は、そのGROUPBY句で指定されていないSELECT句は
                // 一致条件の被演算子に指定されてもテーブル列への一致条件とは見做さない
                for (var i = resultInfoList.Count - 1; i >= 0; --i)
                {
                    if (!this.FindInGroupByItems(query.GroupBy, resultInfoList[i], i))
                    {
                        resultInfoList[i] = new ResultInfo(""
                                                           , resultInfoList[i].ColumnAliasName
                                                           , resultInfoList[i].Node);
                    }
                }
            }
            else
            {
                var aggregateFinder = new FindAggregateExprVisitor();
                query.Results.Accept(aggregateFinder);
                if (aggregateFinder.ContainsAggregativeExpr)
                {
                    // GROUP BY句がなく集約関数がある場合は、全てのSELECT句は
                    // 一致条件の被演算子に指定されてもテーブル列への一致条件とは見做さない
                    for (var i = resultInfoList.Count - 1; i >= 0; --i)
                    {
                        resultInfoList[i] = new ResultInfo(""
                                                           , resultInfoList[i].ColumnAliasName
                                                           , resultInfoList[i].Node);
                    }
                }
            } // if

            _stack.Push(resultInfoList);
        }