1 /********************************************************
\r
2 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
\r
3 * Written by Robert Simpson (robert@blackcastlesoft.com)
\r
5 * Released to the public domain, use at your own risk!
\r
6 ********************************************************/
\r
8 namespace Mono.Data.Sqlite
\r
12 using System.Data.Common;
\r
13 using System.Globalization;
\r
14 using System.ComponentModel;
\r
17 /// SQLite implementation of DbCommandBuilder.
\r
19 public sealed class SqliteCommandBuilder : DbCommandBuilder
\r
22 /// Default constructor
\r
24 public SqliteCommandBuilder() : this(null)
\r
29 /// Initializes the command builder and associates it with the specified data adapter.
\r
31 /// <param name="adp"></param>
\r
32 public SqliteCommandBuilder(SqliteDataAdapter adp)
\r
40 /// Minimal amount of parameter processing. Primarily sets the DbType for the parameter equal to the provider type in the schema
\r
42 /// <param name="parameter">The parameter to use in applying custom behaviors to a row</param>
\r
43 /// <param name="row">The row to apply the parameter to</param>
\r
44 /// <param name="statementType">The type of statement</param>
\r
45 /// <param name="whereClause">Whether the application of the parameter is part of a WHERE clause</param>
\r
46 protected override void ApplyParameterInfo(DbParameter parameter, DataRow row, StatementType statementType, bool whereClause)
\r
48 SqliteParameter param = (SqliteParameter)parameter;
\r
49 param.DbType = (DbType)row[SchemaTableColumn.ProviderType];
\r
53 /// Returns a valid named parameter
\r
55 /// <param name="parameterName">The name of the parameter</param>
\r
56 /// <returns>Error</returns>
\r
57 protected override string GetParameterName(string parameterName)
\r
59 return String.Format(CultureInfo.InvariantCulture, "@{0}", parameterName);
\r
63 /// Returns a named parameter for the given ordinal
\r
65 /// <param name="parameterOrdinal">The i of the parameter</param>
\r
66 /// <returns>Error</returns>
\r
67 protected override string GetParameterName(int parameterOrdinal)
\r
69 return String.Format(CultureInfo.InvariantCulture, "@param{0}", parameterOrdinal);
\r
73 /// Returns a placeholder character for the specified parameter i.
\r
75 /// <param name="parameterOrdinal">The index of the parameter to provide a placeholder for</param>
\r
76 /// <returns>Returns a named parameter</returns>
\r
77 protected override string GetParameterPlaceholder(int parameterOrdinal)
\r
79 return GetParameterName(parameterOrdinal);
\r
83 /// Sets the handler for receiving row updating events. Used by the DbCommandBuilder to autogenerate SQL
\r
84 /// statements that may not have previously been generated.
\r
86 /// <param name="adapter">A data adapter to receive events on.</param>
\r
87 protected override void SetRowUpdatingHandler(DbDataAdapter adapter)
\r
89 if (adapter == base.DataAdapter)
\r
91 ((SqliteDataAdapter)adapter).RowUpdating -= new EventHandler<RowUpdatingEventArgs>(RowUpdatingEventHandler);
\r
95 ((SqliteDataAdapter)adapter).RowUpdating += new EventHandler<RowUpdatingEventArgs>(RowUpdatingEventHandler);
\r
99 private void RowUpdatingEventHandler(object sender, RowUpdatingEventArgs e)
\r
101 base.RowUpdatingHandler(e);
\r
105 /// Gets/sets the DataAdapter for this CommandBuilder
\r
107 public new SqliteDataAdapter DataAdapter
\r
109 get { return (SqliteDataAdapter)base.DataAdapter; }
\r
110 set { base.DataAdapter = value; }
\r
114 /// Returns the automatically-generated SQLite command to delete rows from the database
\r
116 /// <returns></returns>
\r
117 public new SqliteCommand GetDeleteCommand()
\r
119 return (SqliteCommand)base.GetDeleteCommand();
\r
123 /// Returns the automatically-generated SQLite command to delete rows from the database
\r
125 /// <param name="useColumnsForParameterNames"></param>
\r
126 /// <returns></returns>
\r
127 public new SqliteCommand GetDeleteCommand(bool useColumnsForParameterNames)
\r
129 return (SqliteCommand)base.GetDeleteCommand(useColumnsForParameterNames);
\r
133 /// Returns the automatically-generated SQLite command to update rows in the database
\r
135 /// <returns></returns>
\r
136 public new SqliteCommand GetUpdateCommand()
\r
138 return (SqliteCommand)base.GetUpdateCommand();
\r
142 /// Returns the automatically-generated SQLite command to update rows in the database
\r
144 /// <param name="useColumnsForParameterNames"></param>
\r
145 /// <returns></returns>
\r
146 public new SqliteCommand GetUpdateCommand(bool useColumnsForParameterNames)
\r
148 return (SqliteCommand)base.GetUpdateCommand(useColumnsForParameterNames);
\r
152 /// Returns the automatically-generated SQLite command to insert rows into the database
\r
154 /// <returns></returns>
\r
155 public new SqliteCommand GetInsertCommand()
\r
157 return (SqliteCommand)base.GetInsertCommand();
\r
161 /// Returns the automatically-generated SQLite command to insert rows into the database
\r
163 /// <param name="useColumnsForParameterNames"></param>
\r
164 /// <returns></returns>
\r
165 public new SqliteCommand GetInsertCommand(bool useColumnsForParameterNames)
\r
167 return (SqliteCommand)base.GetInsertCommand(useColumnsForParameterNames);
\r
171 /// Overridden to hide its property from the designer
\r
173 #if !PLATFORM_COMPACTFRAMEWORK
\r
176 public override CatalogLocation CatalogLocation
\r
180 return base.CatalogLocation;
\r
184 base.CatalogLocation = value;
\r
189 /// Overridden to hide its property from the designer
\r
191 #if !PLATFORM_COMPACTFRAMEWORK
\r
194 public override string CatalogSeparator
\r
198 return base.CatalogSeparator;
\r
202 base.CatalogSeparator = value;
\r
207 /// Overridden to hide its property from the designer
\r
209 #if !PLATFORM_COMPACTFRAMEWORK
\r
212 [DefaultValue("[")]
\r
213 public override string QuotePrefix
\r
217 return base.QuotePrefix;
\r
221 base.QuotePrefix = value;
\r
226 /// Overridden to hide its property from the designer
\r
228 #if !PLATFORM_COMPACTFRAMEWORK
\r
231 public override string QuoteSuffix
\r
235 return base.QuoteSuffix;
\r
239 base.QuoteSuffix = value;
\r
244 /// Places brackets around an identifier
\r
246 /// <param name="unquotedIdentifier">The identifier to quote</param>
\r
247 /// <returns>The bracketed identifier</returns>
\r
248 public override string QuoteIdentifier(string unquotedIdentifier)
\r
250 if (String.IsNullOrEmpty(QuotePrefix)
\r
251 || String.IsNullOrEmpty(QuoteSuffix)
\r
252 || String.IsNullOrEmpty(unquotedIdentifier))
\r
253 return unquotedIdentifier;
\r
255 return QuotePrefix + unquotedIdentifier.Replace(QuoteSuffix, QuoteSuffix + QuoteSuffix) + QuoteSuffix;
\r
259 /// Removes brackets around an identifier
\r
261 /// <param name="quotedIdentifier">The quoted (bracketed) identifier</param>
\r
262 /// <returns>The undecorated identifier</returns>
\r
263 public override string UnquoteIdentifier(string quotedIdentifier)
\r
265 if (String.IsNullOrEmpty(QuotePrefix)
\r
266 || String.IsNullOrEmpty(QuoteSuffix)
\r
267 || String.IsNullOrEmpty(quotedIdentifier))
\r
268 return quotedIdentifier;
\r
270 if (quotedIdentifier.StartsWith(QuotePrefix, StringComparison.InvariantCultureIgnoreCase) == false
\r
271 || quotedIdentifier.EndsWith(QuoteSuffix, StringComparison.InvariantCultureIgnoreCase) == false)
\r
272 return quotedIdentifier;
\r
274 return quotedIdentifier.Substring(QuotePrefix.Length, quotedIdentifier.Length - (QuotePrefix.Length + QuoteSuffix.Length)).Replace(QuoteSuffix + QuoteSuffix, QuoteSuffix);
\r
278 /// Overridden to hide its property from the designer
\r
280 #if !PLATFORM_COMPACTFRAMEWORK
\r
283 public override string SchemaSeparator
\r
287 return base.SchemaSeparator;
\r
291 base.SchemaSeparator = value;
\r
296 /// Override helper, which can help the base command builder choose the right keys for the given query
\r
298 /// <param name="sourceCommand"></param>
\r
299 /// <returns></returns>
\r
300 protected override DataTable GetSchemaTable(DbCommand sourceCommand)
\r
302 using (IDataReader reader = sourceCommand.ExecuteReader(CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly))
\r
304 DataTable schema = reader.GetSchemaTable();
\r
306 // If the query contains a primary key, turn off the IsUnique property
\r
307 // for all the non-key columns
\r
308 if (HasSchemaPrimaryKey(schema))
\r
309 ResetIsUniqueSchemaColumn(schema);
\r
311 // if table has no primary key we use unique columns as a fall back
\r
316 private bool HasSchemaPrimaryKey(DataTable schema)
\r
318 DataColumn IsKeyColumn = schema.Columns[SchemaTableColumn.IsKey];
\r
320 foreach (DataRow schemaRow in schema.Rows)
\r
322 if ((bool)schemaRow[IsKeyColumn] == true)
\r
329 private void ResetIsUniqueSchemaColumn(DataTable schema)
\r
331 DataColumn IsUniqueColumn = schema.Columns[SchemaTableColumn.IsUnique];
\r
332 DataColumn IsKeyColumn = schema.Columns[SchemaTableColumn.IsKey];
\r
334 foreach (DataRow schemaRow in schema.Rows)
\r
336 if ((bool)schemaRow[IsKeyColumn] == false)
\r
337 schemaRow[IsUniqueColumn] = false;
\r
340 schema.AcceptChanges();
\r