Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data.Entity / System / Data / SqlClient / SqlGen / SqlSelectClauseBuilder.cs
blob83d2b247986bd06ce4ac2cef30b875b9668631d0
1 //---------------------------------------------------------------------
2 // <copyright file="SqlSelectClauseBuilder.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //
6 // @owner Microsoft
7 //---------------------------------------------------------------------
9 using System;
10 using System.Collections.Generic;
11 using System.Diagnostics;
13 namespace System.Data.SqlClient.SqlGen
15 /// <summary>
16 /// This class is used for building the SELECT clause of a Sql Statement
17 /// It is used to gather information about required and optional columns
18 /// and whether TOP and DISTINCT should be specified.
19 ///
20 /// The underlying SqlBuilder is used for gathering the required columns.
21 ///
22 /// The list of OptionalColumns is used for gathering the optional columns.
23 /// Whether a given OptionalColumn should be written is known only after the entire
24 /// command tree has been processed.
25 ///
26 /// The IsDistinct property indicates that we want distinct columns.
27 /// This is given out of band, since the input expression to the select clause
28 /// may already have some columns projected out, and we use append-only SqlBuilders.
29 /// The DISTINCT is inserted when we finally write the object into a string.
30 ///
31 /// Also, we have a Top property, which is non-null if the number of results should
32 /// be limited to certain number. It is given out of band for the same reasons as DISTINCT.
33 ///
34 /// </summary>
35 internal class SqlSelectClauseBuilder : SqlBuilder
37 #region Fields and Properties
38 private List<OptionalColumn> m_optionalColumns;
39 internal void AddOptionalColumn(OptionalColumn column)
41 if (m_optionalColumns == null)
43 m_optionalColumns = new List<OptionalColumn>();
45 m_optionalColumns.Add(column);
48 private TopClause m_top;
49 internal TopClause Top
51 get { return m_top; }
52 set
54 Debug.Assert(m_top == null, "SqlSelectStatement.Top has already been set");
55 m_top = value;
59 /// <summary>
60 /// Do we need to add a DISTINCT at the beginning of the SELECT
61 /// </summary>
62 internal bool IsDistinct
64 get;
65 set;
68 /// <summary>
69 /// Whether any columns have been specified.
70 /// </summary>
71 public override bool IsEmpty
73 get { return (base.IsEmpty) && (this.m_optionalColumns == null || this.m_optionalColumns.Count == 0); }
76 private readonly Func<bool> m_isPartOfTopMostStatement;
77 #endregion
79 #region Constructor
80 internal SqlSelectClauseBuilder(Func<bool> isPartOfTopMostStatement)
82 this.m_isPartOfTopMostStatement = isPartOfTopMostStatement;
84 #endregion
86 #region ISqlFragment Members
88 /// <summary>
89 /// Writes the string representing the Select statement:
90 ///
91 /// SELECT (DISTINCT) (TOP topClause) (optionalColumns) (requiredColumns)
92 ///
93 /// If Distinct is specified or this is part of a top most statement
94 /// all optional columns are marked as used.
95 ///
96 /// Optional columns are only written if marked as used.
97 /// In addition, if no required columns are specified and no optional columns are
98 /// marked as used, the first optional column is written.
99 ///
100 /// </summary>
101 /// <param name="writer"></param>
102 /// <param name="sqlGenerator"></param>
103 public override void WriteSql(SqlWriter writer, SqlGenerator sqlGenerator)
105 writer.Write("SELECT ");
106 if (IsDistinct)
108 writer.Write("DISTINCT ");
111 if (this.Top != null)
113 this.Top.WriteSql(writer, sqlGenerator);
116 if (this.IsEmpty)
118 Debug.Assert(false); // we have removed all possibilities of SELECT *.
119 writer.Write("*");
121 else
123 //Print the optional columns if any
124 bool printedAny = WriteOptionalColumns(writer, sqlGenerator);
126 if (!base.IsEmpty)
128 if (printedAny)
130 writer.Write(", ");
132 base.WriteSql(writer, sqlGenerator);
134 //If no optional columns were printed and there were no other columns,
135 // print at least the first optional column
136 else if (!printedAny)
138 this.m_optionalColumns[0].MarkAsUsed();
139 m_optionalColumns[0].WriteSqlIfUsed(writer, sqlGenerator, "");
144 #endregion
146 #region Private Helper Methods
148 /// <summary>
149 /// Writes the optional columns that are used.
150 /// If this is the topmost statement or distict is specifed as part of the same statement
151 /// all optoinal columns are written.
152 /// </summary>
153 /// <param name="writer"></param>
154 /// <param name="sqlGenerator"></param>
155 /// <returns>Whether at least one column got written</returns>
156 private bool WriteOptionalColumns(SqlWriter writer, SqlGenerator sqlGenerator)
158 if (this.m_optionalColumns == null)
160 return false;
163 if (m_isPartOfTopMostStatement() || IsDistinct)
165 foreach (OptionalColumn column in this.m_optionalColumns)
167 column.MarkAsUsed();
171 string separator = "";
172 bool printedAny = false;
173 foreach (OptionalColumn column in this.m_optionalColumns)
175 if (column.WriteSqlIfUsed(writer, sqlGenerator, separator))
177 printedAny = true;
178 separator = ", ";
181 return printedAny;
183 #endregion