SqlCommandBuilder.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. //------------------------------------------------------------------------------
  2. // <copyright file="SqlCommandBuilder.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. //------------------------------------------------------------------------------
  8. namespace System.Data.SqlClient {
  9. using System;
  10. using System.Collections;
  11. using System.ComponentModel;
  12. using System.Data;
  13. using System.Data.Common;
  14. using System.Data.Sql;
  15. using System.Data.SqlTypes;
  16. using System.Diagnostics;
  17. using System.Globalization;
  18. using System.Text;
  19. using System.Runtime.CompilerServices;
  20. using System.Threading;
  21. public sealed class SqlCommandBuilder : DbCommandBuilder {
  22. public SqlCommandBuilder() : base() {
  23. GC.SuppressFinalize(this);
  24. base.QuotePrefix = "["; // initialize base with defaults
  25. base.QuoteSuffix = "]";
  26. }
  27. public SqlCommandBuilder(SqlDataAdapter adapter) : this() {
  28. DataAdapter = adapter;
  29. }
  30. /// <devnote>SqlServer only supports CatalogLocation.Start</devnote>
  31. [
  32. Browsable(false),
  33. EditorBrowsableAttribute(EditorBrowsableState.Never) ,
  34. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  35. ]
  36. public override CatalogLocation CatalogLocation {
  37. get {
  38. return CatalogLocation.Start;
  39. }
  40. set {
  41. if (CatalogLocation.Start != value) {
  42. throw ADP.SingleValuedProperty("CatalogLocation", "Start");
  43. }
  44. }
  45. }
  46. /// <devnote>SqlServer only supports '.'</devnote>
  47. [
  48. Browsable(false),
  49. EditorBrowsableAttribute(EditorBrowsableState.Never),
  50. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  51. ]
  52. public override string CatalogSeparator {
  53. get {
  54. return ".";
  55. }
  56. set {
  57. if ("." != value) {
  58. throw ADP.SingleValuedProperty("CatalogSeparator", ".");
  59. }
  60. }
  61. }
  62. [
  63. DefaultValue(null),
  64. ResCategoryAttribute(Res.DataCategory_Update),
  65. ResDescriptionAttribute(Res.SqlCommandBuilder_DataAdapter), // MDAC 60524
  66. ]
  67. new public SqlDataAdapter DataAdapter {
  68. get {
  69. return (SqlDataAdapter)base.DataAdapter;
  70. }
  71. set {
  72. base.DataAdapter = value;
  73. }
  74. }
  75. /// <devnote>SqlServer only supports '.'</devnote>
  76. [
  77. Browsable(false),
  78. EditorBrowsableAttribute(EditorBrowsableState.Never),
  79. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  80. ]
  81. public override string QuotePrefix {
  82. get {
  83. return base.QuotePrefix;
  84. }
  85. set {
  86. if (("[" != value) && ("\"" != value)){
  87. throw ADP.DoubleValuedProperty("QuotePrefix", "[", "\"");
  88. }
  89. base.QuotePrefix = value;
  90. }
  91. }
  92. [
  93. Browsable(false),
  94. EditorBrowsableAttribute(EditorBrowsableState.Never),
  95. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  96. ]
  97. public override string QuoteSuffix {
  98. get {
  99. return base.QuoteSuffix;
  100. }
  101. set {
  102. if (("]" != value) && ("\"" != value)) {
  103. throw ADP.DoubleValuedProperty("QuoteSuffix", "]", "\"");
  104. }
  105. base.QuoteSuffix = value;
  106. }
  107. }
  108. [
  109. Browsable(false),
  110. EditorBrowsableAttribute(EditorBrowsableState.Never),
  111. DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  112. ]
  113. public override string SchemaSeparator {
  114. get {
  115. return ".";
  116. }
  117. set {
  118. if ("." != value) {
  119. throw ADP.SingleValuedProperty("SchemaSeparator",".");
  120. }
  121. }
  122. }
  123. private void SqlRowUpdatingHandler(object sender, SqlRowUpdatingEventArgs ruevent) {
  124. base.RowUpdatingHandler(ruevent);
  125. }
  126. new public SqlCommand GetInsertCommand() {
  127. return (SqlCommand) base.GetInsertCommand();
  128. }
  129. new public SqlCommand GetInsertCommand(bool useColumnsForParameterNames) {
  130. return (SqlCommand) base.GetInsertCommand(useColumnsForParameterNames);
  131. }
  132. new public SqlCommand GetUpdateCommand() {
  133. return (SqlCommand) base.GetUpdateCommand();
  134. }
  135. new public SqlCommand GetUpdateCommand(bool useColumnsForParameterNames) {
  136. return (SqlCommand) base.GetUpdateCommand(useColumnsForParameterNames);
  137. }
  138. new public SqlCommand GetDeleteCommand() {
  139. return (SqlCommand) base.GetDeleteCommand();
  140. }
  141. new public SqlCommand GetDeleteCommand(bool useColumnsForParameterNames) {
  142. return (SqlCommand) base.GetDeleteCommand(useColumnsForParameterNames);
  143. }
  144. override protected void ApplyParameterInfo(DbParameter parameter, DataRow datarow, StatementType statementType, bool whereClause) {
  145. SqlParameter p = (SqlParameter) parameter;
  146. object valueType = datarow[SchemaTableColumn.ProviderType];
  147. p.SqlDbType = (SqlDbType) valueType;
  148. p.Offset = 0;
  149. if ((p.SqlDbType == SqlDbType.Udt) && !p.SourceColumnNullMapping) {
  150. p.UdtTypeName = datarow["DataTypeName"] as string;
  151. }
  152. else {
  153. p.UdtTypeName = String.Empty;
  154. }
  155. object bvalue = datarow[SchemaTableColumn.NumericPrecision];
  156. if (DBNull.Value != bvalue) {
  157. byte bval = (byte)(short)bvalue;
  158. p.PrecisionInternal = ((0xff != bval) ? bval : (byte)0);
  159. }
  160. bvalue = datarow[SchemaTableColumn.NumericScale];
  161. if (DBNull.Value != bvalue) {
  162. byte bval = (byte)(short)bvalue;
  163. p.ScaleInternal = ((0xff != bval) ? bval : (byte)0);
  164. }
  165. }
  166. override protected string GetParameterName(int parameterOrdinal) {
  167. return "@p" + parameterOrdinal.ToString(System.Globalization.CultureInfo.InvariantCulture);
  168. }
  169. override protected string GetParameterName(string parameterName) {
  170. return "@" + parameterName;
  171. }
  172. override protected string GetParameterPlaceholder(int parameterOrdinal) {
  173. return "@p" + parameterOrdinal.ToString(System.Globalization.CultureInfo.InvariantCulture);
  174. }
  175. private void ConsistentQuoteDelimiters(string quotePrefix, string quoteSuffix){
  176. Debug.Assert(quotePrefix == "\"" || quotePrefix == "[");
  177. if ((("\"" == quotePrefix) && ("\"" != quoteSuffix)) ||
  178. (("[" == quotePrefix) && ("]" != quoteSuffix))) {
  179. throw ADP.InvalidPrefixSuffix();
  180. }
  181. }
  182. static public void DeriveParameters(SqlCommand command) { // MDAC 65927\
  183. SqlConnection.ExecutePermission.Demand();
  184. if (null == command) {
  185. throw ADP.ArgumentNull("command");
  186. }
  187. TdsParser bestEffortCleanupTarget = null;
  188. RuntimeHelpers.PrepareConstrainedRegions();
  189. try {
  190. #if DEBUG
  191. TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
  192. RuntimeHelpers.PrepareConstrainedRegions();
  193. try {
  194. tdsReliabilitySection.Start();
  195. #else
  196. {
  197. #endif
  198. bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(command.Connection);
  199. command.DeriveParameters();
  200. }
  201. #if DEBUG
  202. finally {
  203. tdsReliabilitySection.Stop();
  204. }
  205. #endif
  206. }
  207. catch (System.OutOfMemoryException e) {
  208. if (null != command && null != command.Connection) {
  209. command.Connection.Abort(e);
  210. }
  211. throw;
  212. }
  213. catch (System.StackOverflowException e) {
  214. if (null != command && null != command.Connection) {
  215. command.Connection.Abort(e);
  216. }
  217. throw;
  218. }
  219. catch (System.Threading.ThreadAbortException e) {
  220. if (null != command && null != command.Connection) {
  221. command.Connection.Abort(e);
  222. }
  223. SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
  224. throw;
  225. }
  226. }
  227. /* private static void GetLiteralInfo (DataRow dataTypeRow, out string literalPrefix, out string literalSuffix) {
  228. Object tempValue = dataTypeRow[DbMetaDataColumnNames.LiteralPrefix];
  229. if (tempValue == DBNull.Value) {
  230. literalPrefix = "";
  231. }
  232. else {
  233. literalPrefix = (string)dataTypeRow[DbMetaDataColumnNames.LiteralPrefix];
  234. }
  235. tempValue = dataTypeRow[DbMetaDataColumnNames.LiteralSuffix];
  236. if (tempValue == DBNull.Value) {
  237. literalSuffix = "";
  238. }
  239. else {
  240. literalSuffix = (string)dataTypeRow[DbMetaDataColumnNames.LiteralSuffix];
  241. }
  242. }
  243. */
  244. protected override DataTable GetSchemaTable (DbCommand srcCommand) {
  245. SqlCommand sqlCommand = srcCommand as SqlCommand;
  246. SqlNotificationRequest notificationRequest = sqlCommand.Notification;
  247. bool notificationAutoEnlist = sqlCommand.NotificationAutoEnlist;
  248. sqlCommand.Notification = null;
  249. sqlCommand.NotificationAutoEnlist = false;
  250. try {
  251. using (SqlDataReader dataReader = sqlCommand.ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo)){
  252. return dataReader.GetSchemaTable();
  253. }
  254. }
  255. finally {
  256. sqlCommand.Notification = notificationRequest;
  257. sqlCommand.NotificationAutoEnlist = notificationAutoEnlist;
  258. }
  259. }
  260. protected override DbCommand InitializeCommand(DbCommand command) {
  261. SqlCommand cmd = (SqlCommand) base.InitializeCommand(command);
  262. cmd.NotificationAutoEnlist = false;
  263. return cmd;
  264. }
  265. public override string QuoteIdentifier(string unquotedIdentifier){
  266. ADP.CheckArgumentNull(unquotedIdentifier, "unquotedIdentifier");
  267. string quoteSuffixLocal = QuoteSuffix;
  268. string quotePrefixLocal = QuotePrefix;
  269. ConsistentQuoteDelimiters(quotePrefixLocal, quoteSuffixLocal);
  270. return ADP.BuildQuotedString(quotePrefixLocal,quoteSuffixLocal,unquotedIdentifier);;
  271. }
  272. override protected void SetRowUpdatingHandler(DbDataAdapter adapter) {
  273. Debug.Assert(adapter is SqlDataAdapter, "!SqlDataAdapter");
  274. if (adapter == base.DataAdapter) { // removal case
  275. ((SqlDataAdapter)adapter).RowUpdating -= SqlRowUpdatingHandler;
  276. }
  277. else { // adding case
  278. ((SqlDataAdapter)adapter).RowUpdating += SqlRowUpdatingHandler;
  279. }
  280. }
  281. public override string UnquoteIdentifier(string quotedIdentifier){
  282. ADP.CheckArgumentNull(quotedIdentifier, "quotedIdentifier");
  283. String unquotedIdentifier;
  284. string quoteSuffixLocal = QuoteSuffix;
  285. string quotePrefixLocal = QuotePrefix;
  286. ConsistentQuoteDelimiters(quotePrefixLocal, quoteSuffixLocal);
  287. // ignoring the return value becasue an unquoted source string is OK here
  288. ADP.RemoveStringQuotes(quotePrefixLocal, quoteSuffixLocal, quotedIdentifier, out unquotedIdentifier);
  289. return unquotedIdentifier;
  290. }
  291. }
  292. }