Added Mono.Data.Sqlite to build. Restored the sealed classes
[mono.git] / mcs / class / Mono.Data.Sqlite / Mono.Data.Sqlite_2.0 / SQLiteCommandBuilder.cs
1 //
2 // Mono.Data.Sqlite.SQLiteCommandBuilder.cs
3 //
4 // Author(s):
5 //   Robert Simpson (robert@blackcastlesoft.com)
6 //
7 // Adapted and modified for the Mono Project by
8 //   Marek Habersack (grendello@gmail.com)
9 //
10 //
11 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
12 // Copyright (C) 2007 Marek Habersack
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 /********************************************************
35  * ADO.NET 2.0 Data Provider for Sqlite Version 3.X
36  * Written by Robert Simpson (robert@blackcastlesoft.com)
37  * 
38  * Released to the public domain, use at your own risk!
39  ********************************************************/
40 #if NET_2_0
41 namespace Mono.Data.Sqlite
42 {
43   using System;
44   using System.Data;
45   using System.Data.Common;
46   using System.Globalization;
47   using System.ComponentModel;
48
49   /// <summary>
50   /// Sqlite implementation of DbCommandBuilder.
51   /// </summary>
52   public sealed class SqliteCommandBuilder : DbCommandBuilder
53   {
54     private EventHandler<RowUpdatingEventArgs> _handler;
55
56     /// <summary>
57     /// Default constructor
58     /// </summary>
59     public SqliteCommandBuilder() : this(null)
60     {
61     }
62
63     /// <summary>
64     /// Initializes the command builder and associates it with the specified data adapter.
65     /// </summary>
66     /// <param name="adp"></param>
67     public SqliteCommandBuilder(SqliteDataAdapter adp)
68     {
69       QuotePrefix = "[";
70       QuoteSuffix = "]";
71       DataAdapter = adp;
72     }
73
74     /// <summary>
75     /// Minimal amount of parameter processing.  Primarily sets the DbType for the parameter equal to the provider type in the schema
76     /// </summary>
77     /// <param name="parameter">The parameter to use in applying custom behaviors to a row</param>
78     /// <param name="row">The row to apply the parameter to</param>
79     /// <param name="statementType">The type of statement</param>
80     /// <param name="whereClause">Whether the application of the parameter is part of a WHERE clause</param>
81     protected override void ApplyParameterInfo(DbParameter parameter, DataRow row, StatementType statementType, bool whereClause)
82     {
83       SqliteParameter param = (SqliteParameter)parameter;
84       param.DbType = (DbType)row[SchemaTableColumn.ProviderType];
85     }
86
87     /// <summary>
88     /// Returns a valid named parameter
89     /// </summary>
90     /// <param name="parameterName">The name of the parameter</param>
91     /// <returns>Error</returns>
92     protected override string GetParameterName(string parameterName)
93     {
94       return String.Format(CultureInfo.InvariantCulture, "@{0}", parameterName);
95     }
96
97     /// <summary>
98     /// Returns a named parameter for the given ordinal
99     /// </summary>
100     /// <param name="parameterOrdinal">The i of the parameter</param>
101     /// <returns>Error</returns>
102     protected override string GetParameterName(int parameterOrdinal)
103     {
104       return String.Format(CultureInfo.InvariantCulture, "@param{0}", parameterOrdinal);
105     }
106
107     /// <summary>
108     /// Returns a placeholder character for the specified parameter i.
109     /// </summary>
110     /// <param name="parameterOrdinal">The index of the parameter to provide a placeholder for</param>
111     /// <returns>Returns a named parameter</returns>
112     protected override string GetParameterPlaceholder(int parameterOrdinal)
113     {
114       return GetParameterName(parameterOrdinal);
115     }
116
117     /// <summary>
118     /// Sets the handler for receiving row updating events.  Used by the DbCommandBuilder to autogenerate SQL
119     /// statements that may not have previously been generated.
120     /// </summary>
121     /// <param name="adapter">A data adapter to receive events on.</param>
122     protected override void SetRowUpdatingHandler(DbDataAdapter adapter)
123     {
124       SqliteDataAdapter adp = (SqliteDataAdapter)adapter;
125
126       _handler = new EventHandler<RowUpdatingEventArgs>(RowUpdatingEventHandler);
127       adp.RowUpdating += _handler;
128     }
129
130     private void RowUpdatingEventHandler(object sender, RowUpdatingEventArgs e)
131     {
132       base.RowUpdatingHandler(e);
133     }
134
135     /// <summary>
136     /// Gets/sets the DataAdapter for this CommandBuilder
137     /// </summary>
138     public new SqliteDataAdapter DataAdapter
139     {
140       get { return (SqliteDataAdapter)base.DataAdapter; }
141       set { base.DataAdapter = value; }
142     }
143
144     /// <summary>
145     /// Returns the automatically-generated Sqlite command to delete rows from the database
146     /// </summary>
147     /// <returns></returns>
148     public new SqliteCommand GetDeleteCommand()
149     {
150       return (SqliteCommand)base.GetDeleteCommand();
151     }
152
153     /// <summary>
154     /// Returns the automatically-generated Sqlite command to delete rows from the database
155     /// </summary>
156     /// <param name="useColumnsForParameterNames"></param>
157     /// <returns></returns>
158     public new SqliteCommand GetDeleteCommand(bool useColumnsForParameterNames)
159     {
160       return (SqliteCommand)base.GetDeleteCommand(useColumnsForParameterNames);
161     }
162
163     /// <summary>
164     /// Returns the automatically-generated Sqlite command to update rows in the database
165     /// </summary>
166     /// <returns></returns>
167     public new SqliteCommand GetUpdateCommand()
168     {
169       return (SqliteCommand)base.GetUpdateCommand();
170     }
171
172     /// <summary>
173     /// Returns the automatically-generated Sqlite command to update rows in the database
174     /// </summary>
175     /// <param name="useColumnsForParameterNames"></param>
176     /// <returns></returns>
177     public new SqliteCommand GetUpdateCommand(bool useColumnsForParameterNames)
178     {
179       return (SqliteCommand)base.GetUpdateCommand(useColumnsForParameterNames);
180     }
181
182     /// <summary>
183     /// Returns the automatically-generated Sqlite command to insert rows into the database
184     /// </summary>
185     /// <returns></returns>
186     public new SqliteCommand GetInsertCommand()
187     {
188       return (SqliteCommand)base.GetInsertCommand();
189     }
190
191     /// <summary>
192     /// Returns the automatically-generated Sqlite command to insert rows into the database
193     /// </summary>
194     /// <param name="useColumnsForParameterNames"></param>
195     /// <returns></returns>
196     public new SqliteCommand GetInsertCommand(bool useColumnsForParameterNames)
197     {
198       return (SqliteCommand)base.GetInsertCommand(useColumnsForParameterNames);
199     }
200
201     /// <summary>
202     /// Overridden to hide its property from the designer
203     /// </summary>
204 #if !PLATFORM_COMPACTFRAMEWORK
205     [Browsable(false)]
206 #endif
207     public override CatalogLocation CatalogLocation
208     {
209       get
210       {
211         return base.CatalogLocation;
212       }
213       set
214       {
215         base.CatalogLocation = value;
216       }
217     }
218
219     /// <summary>
220     /// Overridden to hide its property from the designer
221     /// </summary>
222 #if !PLATFORM_COMPACTFRAMEWORK
223     [Browsable(false)]
224 #endif
225     public override string CatalogSeparator
226     {
227       get
228       {
229         return base.CatalogSeparator;
230       }
231       set
232       {
233         base.CatalogSeparator = value;
234       }
235     }
236
237     /// <summary>
238     /// Overridden to hide its property from the designer
239     /// </summary>
240 #if !PLATFORM_COMPACTFRAMEWORK
241     [Browsable(false)]
242 #endif
243     [DefaultValue("[")]
244     public override string QuotePrefix
245     {
246       get
247       {
248         return base.QuotePrefix;
249       }
250       set
251       {
252         base.QuotePrefix = value;
253       }
254     }
255
256     /// <summary>
257     /// Overridden to hide its property from the designer
258     /// </summary>
259 #if !PLATFORM_COMPACTFRAMEWORK
260     [Browsable(false)]
261 #endif
262     public override string QuoteSuffix
263     {
264       get
265       {
266         return base.QuoteSuffix;
267       }
268       set
269       {
270         base.QuoteSuffix = value;
271       }
272     }
273
274     /// <summary>
275     /// Places brackets around an identifier
276     /// </summary>
277     /// <param name="unquotedIdentifier">The identifier to quote</param>
278     /// <returns>The bracketed identifier</returns>
279     public override string QuoteIdentifier(string unquotedIdentifier)
280     {
281       if (String.IsNullOrEmpty(QuotePrefix)
282         || String.IsNullOrEmpty(QuoteSuffix)
283         || String.IsNullOrEmpty(unquotedIdentifier))
284         return unquotedIdentifier;
285
286       return QuotePrefix + unquotedIdentifier.Replace(QuoteSuffix, QuoteSuffix + QuoteSuffix) + QuoteSuffix;
287     }
288
289     /// <summary>
290     /// Removes brackets around an identifier
291     /// </summary>
292     /// <param name="quotedIdentifier">The quoted (bracketed) identifier</param>
293     /// <returns>The undecorated identifier</returns>
294     public override string UnquoteIdentifier(string quotedIdentifier)
295     {
296       if (String.IsNullOrEmpty(QuotePrefix)
297         || String.IsNullOrEmpty(QuoteSuffix)
298         || String.IsNullOrEmpty(quotedIdentifier))
299         return quotedIdentifier;
300
301       if (quotedIdentifier.StartsWith(QuotePrefix, StringComparison.InvariantCultureIgnoreCase) == false
302         || quotedIdentifier.EndsWith(QuoteSuffix, StringComparison.InvariantCultureIgnoreCase) == false)
303         return quotedIdentifier;
304
305       return quotedIdentifier.Substring(QuotePrefix.Length, quotedIdentifier.Length - (QuotePrefix.Length + QuoteSuffix.Length)).Replace(QuoteSuffix + QuoteSuffix, QuoteSuffix);
306     }
307
308     /// <summary>
309     /// Overridden to hide its property from the designer
310     /// </summary>
311 #if !PLATFORM_COMPACTFRAMEWORK
312     [Browsable(false)]
313 #endif
314     public override string SchemaSeparator
315     {
316       get
317       {
318         return base.SchemaSeparator;
319       }
320       set
321       {
322         base.SchemaSeparator = value;
323       }
324     }
325
326     /// <summary>
327     /// Override helper, which can help the base command builder choose the right keys for the given query
328     /// </summary>
329     /// <param name="sourceCommand"></param>
330     /// <returns></returns>
331     protected override DataTable GetSchemaTable(DbCommand sourceCommand)
332     {
333       using (IDataReader reader = sourceCommand.ExecuteReader(CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly))
334       {
335         DataTable schema = reader.GetSchemaTable();
336
337         // If the query contains a primary key, turn off the IsUnique property
338         // for all the non-key columns
339         if (HasSchemaPrimaryKey(schema))
340           ResetIsUniqueSchemaColumn(schema);
341
342         // if table has no primary key we use unique columns as a fall back
343         return schema;
344       }
345     }
346
347     private bool HasSchemaPrimaryKey(DataTable schema)
348     {
349       DataColumn IsKeyColumn = schema.Columns[SchemaTableColumn.IsKey];
350       
351       foreach (DataRow schemaRow in schema.Rows)
352       {
353         if ((bool)schemaRow[IsKeyColumn] == true)
354           return true;
355       }
356
357       return false;
358     }
359
360     private void ResetIsUniqueSchemaColumn(DataTable schema)
361     {
362       DataColumn IsUniqueColumn = schema.Columns[SchemaTableColumn.IsUnique];
363       DataColumn IsKeyColumn = schema.Columns[SchemaTableColumn.IsKey];
364
365       foreach (DataRow schemaRow in schema.Rows)
366       {
367         if ((bool)schemaRow[IsKeyColumn] == false)
368           schemaRow[IsUniqueColumn] = false;
369       }
370
371       schema.AcceptChanges();
372     }
373   }
374 }
375 #endif